AngularJS передает параметры в шаблоне директивы контроллеру
В моем приложении у меня есть такие директивы:
.directive('nodeList', function($compile) {
return {
restrict: 'E',
terminal: true,
scope: {
nodes: '=ngModel',
deleteArticle: '&',
editArticle: '&'
},
link: function ($scope, $element, $attrs) {
if (angular.isArray($scope.nodes)) {
$element.append('<accordion close-others="true"><node ng-repeat="item in nodes" ng-model="item" delete-article="deleteArticle(node_item)" edit-article="editArticle(node_item)"></node></accordion>');
}
$compile($element.contents())($scope.$new());
}
};
})
.directive('node', function($compile) {
return {
restrict: 'E',
terminal: true,
scope: {
node: '=ngModel',
deleteArticle: '&',
editArticle: '&'
},
link: function ($scope, $element, $attrs) {
if (angular.isArray($scope.node.Options) && $scope.node.Options.length > 0) {
$element.append('<accordion-group><accordion-heading>{{node.Title}} <a href="javascript:void(0)" ng-click="editArticle({node_item: node})" data-toggle="modal" data-target="#new-article" class="action"><i class="glyphicon glyphicon-edit"></i></a></accordion-heading><node-list ng-model="node.Options"></node-list>{{node.Content}}</accordion-group>');
} else {
$element.append('<accordion-group><accordion-heading>{{node.Title}} <a href="javascript:void(0)" ng-click="editArticle({node_item: node})" data-toggle="modal" data-target="#new-article" class="action"><i class="glyphicon glyphicon-edit"></i></a></accordion-heading>{{node.Content}}</accordion-group>');
}
$compile($element.contents())($scope.$new());
}
};
})
И такой html:
<node-list ng-model="articles" delete-article="deleteArticle(node_item)" edit-article="editArticle(node_item)"></node-list>
И в контроллере:
$scope.editArticle = function(vArticle) {}
Когда у меня есть только одна директива-все понятно, но как передать параметры, когда моя директива вызывает другую директиву? это реально? и каким образом?
4 ответов:
Вам просто нужно изменить очень маленький кусочек вашего кода, чтобы ваш вызов функции получил аргумент правильно
В вашей директиве nodeList вызовите ваш узел следующим образом:
<node ng-repeat="item in nodes" ng-model="item" delete-article="deleteArticle({node_item: node_item})" edit-article="editArticle({node_item: node_item})"></node>И в вашей директиве node вызовите свой nodeList следующим образом:
<node-list ng-model="node.Options" delete-article="deleteArticle({node_item: node_item})" edit-article="editArticle({node_item: node_item})"></node-list>Так что ссылка "node_item" передается правильно среди детей детей детей... к самому верхнему родителю (ваш контроллер:)
Взгляните на это: плунжер
Причина:
Ваш
имеет свою собственную область, вам нужно передать "node_item" в родительскую область (ваш контроллер), просто! Сложность заключается в том, что функция вызывается внутри области внука ( ), поэтому вам снова нужно передать "node_item" от внука к ребенку. Вам также не нужно создавать новую область видимости при вызове compile. Объект $ scope, который у вас есть, также был новая область из родительской области.
Вы можете взаимодействовать между директивами, используя контроллер и делая эту зависимость явной. Простой пример:
var myApp = angular.module('myApp', []) .directive('foo', function () { return { restrict: 'E', controller: function ($scope) { this.property = 'something'; }, link: function (scope, element) { } }; }) .directive('bar', function() { return { require: '^foo', link: function (scope, element, attrs, fooCtrl) { console.log(fooCtrl.property); scope.value = fooCtrl.property; } } })Здесь директива
barобъявляет зависимость от директивыfooкак заключающую директиву. Поэтому директивы могут взаимодействовать, так как функция link передает дополнительный аргумент. Поэтому этот HTML-фрагмент будет отображатьsomething:<div ng-app="myApp"> <foo><bar>{{ value }}</bar></foo> </div>Вы можете играть с этим примером в этом JSFiddle.
Директива NodeList
Предоставьте API контроллера из вашей директивы nodeList, которую ваши дочерние директивы узлов могут вызывать для удаления или редактирования статьи.
controller: function ($scope) { this.deleteArticle = function (node) { var index = $scope.nodes.indexOf(node); if (index >= 0) { $scope.nodes.splice(index, 1); $scope.$emit('articleDeleted', node); } } this.editArticle = function (node) { var index = $scope.nodes.indexOf(node); if (index >= 0) { $scope.$emit('articleEdited', node); } } }Директива Узла
В директиве node вручную скомпилируйте директиву nodeList, чтобы избежать рекурсии, и добавьте ссылки для вызова API контроллера nodeList:
link: function ($scope, $element, $attrs, nodeListController) { var template = angular.element('<node-list ng-model="node.nodes" ng-hide="node.hidden"></node-list>'); $element.append(template); $compile(template)($scope); $scope.delete = function (node) { nodeListController.deleteArticle(node); } $scope.edit = function (node) { nodeListController.editArticle(node); } }Родительский Контроллер:
Используйте
$emitдля уведомления пользователей о том, что узел был изменен или удален.$scope.$on('articleEdited', function (evt, node) { alert('Edited ' + node.Title); }); $scope.$on('articleDeleted', function (evt, node) { alert('Deleted ' + node.Title); });
var app = angular.module('app', []); var ctrl = app.controller('ctrl', function($scope, $rootScope) { $scope.nodes = [{ Title: 'Title 1', nodes: [{ Title: 'Title 1.1', nodes: [] }, { Title: 'Title 1.2', nodes: [] }] }, { Title: 'Title 2', nodes: [{ Title: 'Title 2.1', nodes: [{ Title: 'Title 2.1.1', nodes: [] }, { Title: 'Title 2.1.2', nodes: [] }] }, { Title: 'Title 2.2', nodes: [{ Title: 'Title 2.2.1', nodes: [] }, { Title: 'Title 2.2.2', nodes: [] }, { Title: 'Title 2.2.3', nodes: [] }, { Title: 'Title 2.2.4', nodes: [] }] }] }]; $scope.$on('articleEdited', function(evt, node) { alert('Edited ' + node.Title); }); $scope.$on('articleDeleted', function(evt, node) { alert('Deleted ' + node.Title); }); }); app.directive('nodeList', function($parse) { return { restrict: 'E', scope: { nodes: '=ngModel' }, template: '<div close-others="true"><node ng-repeat="item in nodes" ng-model="item" ></node></div>', controller: function($scope) { this.deleteArticle = function(node) { var index = $scope.nodes.indexOf(node); if (index >= 0) { $scope.nodes.splice(index, 1); $scope.$emit('articleDeleted', node); } } this.editArticle = function(node) { var index = $scope.nodes.indexOf(node); if (index >= 0) { $scope.$emit('articleEdited', node); } } }, link: function($scope, $element, $attrs) {} }; }); app.directive('node', function($compile) { return { restrict: 'E', require: '^nodeList', scope: { node: '=ngModel' }, controller: function($scope) { }, template: '<div><span ng-click="node.hidden = !node.hidden">{{node.Title}}</span><a href="#" ng-click="edit(node)">Edit</a> <a href="#" ng-click="delete(node)">Delete</a></div>', link: function($scope, $element, $attrs, nodeListController) { var template = angular.element('<node-list ng-model="node.nodes" ng-hide="node.hidden"></node-list>'); $element.append(template); $compile(template)($scope); $scope.delete = function(node) { nodeListController.deleteArticle(node); } $scope.edit = function(node) { nodeListController.editArticle(node); } } }; });div { margin-left: 20px; }<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> </head> <body ng-app="app" ng-controller="ctrl"> <node-list ng-model="nodes"> </node-list> </body> </html>
Вы можете использовать сервис для передачи любого параметра, который вы используете Вам нужно будет добавить триггер, чтобы получить информацию при создании директивы этот триггер должен получить информацию от сервиса и использовать ее Если он будет создан и получит неопределенный параметр, то это будет первая директива
У меня нет рабочего кода, но эта концепция будет работать.
Comments