Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get number of child directives in parent directive before link function is executed

When using one directive & multiple child directives (using require), what is a way to know how many child directives will be executed?

I could just count each time the child directive is executed (in the link function). But I want the parent directive to know how many childs there are before the last link function is executed of the child directive.

I need to know because I need some specific behaviour when the last element is passed from the child to the parent directive..

like image 231
Vincent Avatar asked Dec 05 '14 13:12

Vincent


3 Answers

You can take advantage of the fact that linking is done in two phases. You could first register all children in "pre-link phase" and then, in "post-link phase", you'd have access to the required information.

.directive('parent', function () {
    return {
        controller: function () {
            this.childCount = {
                pre: 0,
                post: 0
            };
        },
        link: function () {}
    };
})
.directive('child', function () {
    return {
        require: '^parent',
        compile: function () {
            return {
                pre: function ($scope, $element, $attrs, parentCtrl) {
                    ++parentCtrl.childCount.pre;
                },
                post: function ($scope, $element, $attrs, parentCtrl) {
                    ++parentCtrl.childCount.post;
                    if (parentCtrl.childCount.post === parentCtrl.childCount.pre) {
                        // ... (this runs only on the last linked child)
                    }
                }
            };
        }
    };
})

This way you have access to that information during last child's linking.

Of course, if you don't need the info that soon, you could just register all child controllers in the parent controller and then run a method of the last registered child controller from the parent post-link function.

like image 91
hon2a Avatar answered Oct 13 '22 00:10

hon2a


I am quite sure, it cant be done without searching DOM under parent directive. But I think its not problem to do that in so specialized directive.

So I would do it like that:

var app = angular.module("app", []);

app.directive("server", function() {
  return {    
    controller: function($element) {                 
      count = $element.find("client").length
      this.call = function() {
        console.log("Server has been called");

        count --;
        if (count == 0) {
          console.log("All of them are initialized");
        }
      };
    }
  };
});

app.directive("client", function() {
  return {
    require: "^server",
    link: function($scope, $elem, $attrs, serverCtrl) {
      serverCtrl.call();
    }
  };
});

And directives looks like that:

 <server>
    <client></client>
    <client></client>
    <client></client>
  </server>

Here you can see full working example: http://jsbin.com/gezewidoba/1/edit?html,js,console

like image 38
Víťa Plšek - angular.cz Avatar answered Oct 13 '22 00:10

Víťa Plšek - angular.cz


The execution sequence of outer and inner directives is as below

Outer - Controller
Child - Controller
Child - Link
Outer - Link

so you can use the child directive's controller to hookup into the parent directive's controller, thru some exposed function on parent directive.

And then in the link function of the inner directive, you can have logic to find out if the element is first or last, etc etc...

like image 41
harishr Avatar answered Oct 12 '22 23:10

harishr