7

In my app i have such 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 controller:

$scope.editArticle = function(vArticle) {}

when i have only one directive - all is clear, but how to pass parameters when my directive is calling another directive? is it real? and how?

brabertaser19
  • 5,678
  • 16
  • 78
  • 184

4 Answers4

3

You just need to change a very small piece of you code in order for your function call to receive the argument correctly

in your nodeList directive, call to your node like this:

<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 to your nodeList like this:

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

So the reference "node_item" being passed correctly amongst children of children of children... to the top most parent (your controller:)

Have a look at this: Plunker

The reason:

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

You also don't need to create a new scope when calling compile. The $scope object you have there was also a new scope from the parent scope.

Mr. Duc Nguyen
  • 1,049
  • 7
  • 16
2

You can communicate between directives by using a controller and by making 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, directive bar declares a dependency to directive foo as an enclosing directive. Therefore, the directives can communicate as the link function is passed an additional argument. This HTML snipped will therefore display something:

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

You can play with this example in this JSFiddle.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
0

NodeList Directive

Expose a controller API from your nodeList directive that your child node directives can call to delete or edit an article.

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 call the nodeList controller's 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 a node was 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>
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
-1

You can use a service to pass any parameter that you use You would need to add a trigger to get information when the directive is created this trigger should get the information from the service and use it If it is created and get an undefined parameter it would be the first directive

I don't have a working codebut this concept would work.

Utku Apaydin
  • 162
  • 1
  • 4