Может ли директива angular передавать аргументы в функции в выражениях, указанных в атрибутах директивы?

У меня есть директива формы, которая использует указанный атрибут callback с областью выделения:

scope: { callback: '&' }

Он находится внутри ng-repeat, поэтому выражение, которое я передаю, включает в себя id объекта в качестве аргумента функции обратного вызова:

<directive ng-repeat = "item in stuff" callback = "callback(item.id)"/>

Когда я закончил с директивой, он вызывает $scope.callback() из своей функции контроллера. В большинстве случаев это нормально, и все, что я хочу сделать, но иногда я хотел бы добавить еще один аргумент из самого directive.

Есть ли выражение angular, которое позволит это: $scope.callback(arg2), в результате чего callback вызывается с помощью arguments = [item.id, arg2]?

Если нет, то какой самый простой способ сделать это?

Я обнаружил, что это работает:

<directive 
  ng-repeat = "item in stuff" 
  callback = "callback" 
  callback-arg="item.id"/>

С

scope { callback: '=', callbackArg: '=' }

и директивный вызов

$scope.callback.apply(null, [$scope.callbackArg].concat([arg2, arg3]) );

Но я не думаю, что это особенно опрятно, и это включает в себя добавление лишних вещей в область выделения.

Есть ли лучший способ?

Плункерная площадка здесь (консоль открыта).

Ответ 1

Если вы заявляете свой обратный вызов, как упоминалось в @lex82, например

callback = "callback(item.id, arg2)"

Вы можете вызвать метод обратного вызова в области директивы с помощью карты объектов, и он будет правильно связывать. Как

scope.callback({arg2:"some value"});

не требуя для $parse. Смотрите мою скрипку (консольный журнал) http://jsfiddle.net/k7czc/2/

Обновить. Это небольшой пример этого в документации :

& или & attr - обеспечивает способ выполнения выражения в контексте родительский охват. Если имя attr не указано, имя атрибута предполагается, что оно совпадает с локальным именем. Определенное и видимое определение области: { localFn: '& myAttr'}, затем изолировать свойство scope localFn будет указывать на обертка функций для выражения count = count + value. Часто желательно передавать данные из изолированного объема посредством выражения и в родительскую область, это можно сделать, передав карту локальных имена переменных и значения в оболочку выражения fn. Например, если выражение является приращением (суммой), то мы можем указать сумму значение, вызывая localFn как localFn ({amount: 22}).

Ответ 2

Ничего плохого в других ответах, но я использую следующий метод при передаче функций в атрибуте директивы.

Оставьте круглую скобку, включив директиву в свой html:

<my-directive callback="someFunction" />

Затем "разворачивать" функцию в вашей директивной ссылке или контроллере. вот пример:

app.directive("myDirective", function() {

    return {
        restrict: "E",
        scope: {
            callback: "&"                              
        },
        template: "<div ng-click='callback(data)'></div>", // call function this way...
        link: function(scope, element, attrs) {
            // unwrap the function
            scope.callback = scope.callback(); 

            scope.data = "data from somewhere";

            element.bind("click",function() {
                scope.$apply(function() {
                    callback(data);                        // ...or this way
                });
            });
        }
    }
}]);    

Шаг "разворачивания" позволяет вызывать функцию с использованием более естественного синтаксиса. Это также гарантирует правильность работы директивы, даже если она вложена в другие директивы, которые могут передавать функцию. Если вы не сделали разворачивание, тогда, если у вас есть такой сценарий:

<outer-directive callback="someFunction" >
    <middle-directive callback="callback" >
        <inner-directive callback="callback" />
    </middle-directive>
</outer-directive>

Тогда в вашей внутренней директиве вы получите что-то подобное:

callback()()()(data); 

Что произойдет в других сценариях вложенности.

Я адаптировал этот метод из превосходной статьи Дэна Вахлина в http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parameters

Я добавил шаг развертывания, чтобы сделать вызов функции более естественным и решить проблему размещения, с которой я столкнулся в проекте.

Ответ 3

В директиве (myDirective):

...
directive.scope = {  
    boundFunction: '&',
    model: '=',
};
...
return directive;

В шаблоне директивы:

<div 
data-ng-repeat="item in model"  
data-ng-click='boundFunction({param: item})'>
{{item.myValue}}
</div>

В источнике:

<my-directive 
model='myData' 
bound-function='myFunction(param)'>
</my-directive>

... где myFunction определяется в контроллере.

Обратите внимание, что param в шаблоне директивы аккуратно привязывается к param в источнике и устанавливается на item.


Чтобы вызвать из свойства link директивы ( "внутри" ), используйте очень похожий подход:

...
directive.link = function(isolatedScope) {
    isolatedScope.boundFunction({param: "foo"});
};
...
return directive;

Ответ 4

Да, есть лучший способ: вы можете использовать $parse service в своей директиве для оценки выражения в контексте родительского scope при привязке определенных идентификаторов в выражении к значениям, видимым только внутри вашей директивы:

$parse(attributes.callback)(scope.$parent, { arg2: yourSecondArgument });

Добавьте эту строку в функцию ссылки директивы, где вы можете получить доступ к атрибутам директивы.

Атрибут обратного вызова может быть установлен как callback = "callback(item.id, arg2)", потому что arg2 привязан к вашемуSecondArgument службой $parse внутри директивы. Директивы типа ng-click позволяют вам получить доступ к событию клика с помощью идентификатора $event внутри выражения, переданного в директиву, используя именно этот механизм.

Обратите внимание, что вам не нужно делать callback членом вашей изолированной области с помощью этого решения.

Ответ 5

У меня работает следующее:

в директиве объявить это так:

.directive('myDirective', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            myFunction: '=',
        },
        templateUrl: 'myDirective.html'
    };
})  

В шаблоне директивы используйте его следующим образом:

<select ng-change="myFunction(selectedAmount)">

И затем, когда вы используете директиву, передайте функцию следующим образом:

<data-my-directive
    data-my-function="setSelectedAmount">
</data-my-directive>

Вы передаете функцию по ее объявлению, и она вызывается из директивы, а параметры заполняются.