it-swarm.com.ru

Может ли директива 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]) );

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

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

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

156
Ed Hinchliffe

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

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

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

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

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

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

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

210
Chandermani

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

Не включайте скобки при включении директивы в ваш 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

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

57
ItsCosmo

В директиве (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;
38
Ben

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

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

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

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

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

15
lex82

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

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

.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>

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

0
jabko87