AngularJS passes parameters in the directive template for the controller

In my application, I have the following directives:

.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()); } }; }) 

and such html:

 <node-list ng-model="articles" delete-article="deleteArticle(node_item)" edit-article="editArticle(node_item)"></node-list> 

and in the controller:

 $scope.editArticle = function(vArticle) {} 

when I have only one directive - everything is clear, but how to pass parameters when my directive calls another directive? it's real? And How?

+6
source share
4 answers

You just need to modify a very small piece of code so that your function call gets the argument correctly

in the nodeList directive, call node :

 <node ng-repeat="item in nodes" ng-model="item" delete-article="deleteArticle({node_item: node_item})" edit-article="editArticle({node_item: node_item})"></node> 

and in your node directive, call the List node as follows:

 <node-list ng-model="node.Options" delete-article="deleteArticle({node_item: node_item})" edit-article="editArticle({node_item: node_item})"></node-list> 

So, the link "node_item" is correctly passed among children of children of children ... to the top of the main parent (your controller :)

Take a look at this: Plunker

Cause:

Your <node -list> has its own scope, you need to pass "node_item" to the parent scope (your controller), simply! The tricky part is that the function is called inside the grandson's scope ( <node> ), so again you need to pass the "node_item" from the grandson to the child.

Also, you may not create a new scope when calling compilation. The $ scope object you have also contained the new scope from the parent scope.

+3
source

You can communicate between directives using a controller and make this dependency explicit. A simple example:

 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; } } }) 

Here, the bar directive declares a dependency of the foo directive as an attached directive. Therefore, directives can be bound, because the binding function is passed by an additional argument. Therefore, this HTML snapshot will display something :

 <div ng-app="myApp"> <foo><bar>{{ value }}</bar></foo> </div> 

You can play with this example in this JSFiddle .

+2
source

NodeList Directive

Derive the controller API from the nodeList directive so that your child node directives can cause the article to be deleted or edited.

 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 Directive

In your node directive, manually compile the nodeList directive to avoid recursion, and add links to invoke the nodeList API:

 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); } } 

Parent controller:

Use $emit to notify users of your directive that the node has been edited or deleted.

 $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> 
0
source

You can use the service to transfer any parameter that you use. You will need to add a trigger to receive information when creating the directive. This trigger should receive information from the service and use it. If it is created and receives the undefined parameter, it will be the first directive

I don't have working code, but this concept will work.

-1
source

Source: https://habr.com/ru/post/977750/


All Articles