Может ли угловая директива передавать аргументы функциям в выражениях, указанных в атрибутах директивы?
У меня есть директива формы, которая использует указанный callback
атрибут с изолированной областью:
scope: { callback: '&' }
Он сидит внутри ng-repeat
поэтому выражение, которое я передаю, включает в себя id
объекта в качестве аргумента для функции обратного вызова:
<directive ng-repeat = "item in stuff" callback = "callback(item.id)"/>
Когда я закончил с директивой, она вызывает $scope.callback()
от его функции контроллера. В большинстве случаев это хорошо, и это все, что я хочу сделать, но иногда я хотел бы добавить еще один аргумент изнутри directive
сам.
Есть ли угловое выражение, которое позволило бы это: $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]) );
Но я не думаю, что это особенно опрятно и включает в себя добавление дополнительных вещей в область изоляции.
Есть ли способ лучше?
Здесь есть плункерная площадка (консоль открыта).
4 ответа
Если вы объявите свой обратный вызов как упомянуто @lex82 как
callback = "callback(item.id, arg2)"
Вы можете вызвать метод обратного вызова в области действия директивы с картой объекта, и он будет выполнять привязку правильно. подобно
scope.callback({arg2:"some value"});
не требуя для разбора $. Смотрите мою скрипку (консольный журнал) http://jsfiddle.net/k7czc/2/
Обновление: есть небольшой пример этого в документации:
& или &attr - предоставляет способ выполнить выражение в контексте родительской области. Если имя атрибута не указано, то предполагается, что имя атрибута совпадает с локальным именем. Для данного виджета и определения видимости области: { localFn:'&myAttr' }, то свойство изоляции области localFn будет указывать на функцию-оболочку для выражения count = count + value. Часто желательно передавать данные из изолированной области видимости через выражение и в родительскую область видимости, это можно сделать, передав карту имен и значений локальных переменных в оболочку выражения fn. Например, если выражение является приращением (количеством), то мы можем указать значение суммы, вызвав localFn как localFn({amount: 22}).
В других ответах нет ничего плохого, но я использую следующую технику при передаче функций в атрибуте директивы.
Не включайте скобки при включении директивы в ваш 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
Я добавил шаг развертывания, чтобы сделать вызов функции более естественным и решить проблему с вложенностью, с которой я столкнулся в проекте.
В директиве (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;
Да, есть лучший способ: вы можете использовать службу $ parse в вашей директиве для оценки выражения в контексте родительской области, связывая определенные идентификаторы в выражении со значениями, видимыми только внутри вашей директивы:
$parse(attributes.callback)(scope.$parent, { arg2: yourSecondArgument });
Добавьте эту строку в функцию ссылки директивы, где вы можете получить доступ к атрибутам директивы.
Ваш атрибут обратного вызова может быть установлен как callback = "callback(item.id, arg2)"
потому что arg2 связан с yourSecondArgument службой $ parse внутри директивы. Директивы как ng-click
позволит вам получить доступ к событию клика через $event
идентификатор внутри выражения, переданного директиве с использованием именно этого механизма.
Обратите внимание, что вам не нужно делать callback
член вашей изолированной области с этим решением.
У меня работает следующее:
в директиве объявить это так:
.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>
Вы передаете функцию по ее объявлению, и она вызывается из директивы, а параметры заполняются.