4

I'm trying to figure out something with scope and link when a directive is initialized. I have a directive in a tree controller to display details at a branch point:

<typelists sub="branch.subBranches[0]"></typelists>

The (relevant parts of the) directive that handles that branch info are below:

listsApp.directive(
    'typelists',
    function($rootScope) {
        return {
            restrict: 'EA',
            replace: true,
            scope: {
                branch : '=sub'
            },
            templateUrl: templateDir + '/typelists.html',
            link: function (scope, element, attrs) {
                console.log(scope,scope.branch); // DEBUG

                // other stuff
                //  (including a working reload() and refresh() methods)

                scope.subject = 'Type' + scope.branch.model.getFilter() + 'Lists';

                // catch $rootScope.$broadcasts for this branch
                $rootScope.$on( scope.subject+'Refresh', function() { scope.refresh(); ) } );
                $rootScope.$on( scope.subject+'Reload', function() { scope.reload(); } );
            }
        };

Now, what is confusing the bajeezus out of me is that in the // DEBUG line, I can see .branch populated as expected in the output of the scope alone, but scope.branch shows as undefined. This means that when I try to set scope.subject down below, instead of getting a typeId back from the parent type, I'm getting 'undefined' so instead of getting a unique branch tag such as 'Type1Lists' I'm getting 'TypeundefinedLists', thus my $on watch functions aren't triggering properly.

Why am I unable to access scope.branch or why is it showing as undefined when I try? (especially when I can see it in the same console.log output as part of scope?)

Thanks in advance for any help.

0

2 Answers 2

2

How does branch.subBranches[0] get populated? I bet that value is set just after the link function of the directive runs.

You can either make the directive resilient to these changes, like so:

var unwatch = scope.$watch("scope.branch", function(v){
  if (v) {
    unwatch(); // removes the watch when value is not undefined
    init(); // run your init code
  }
});

Or, only instantiate the directive when the data is ready:

<typelists ng-if="branch.subBranches[0] !== undefined" 
           sub="branch.subBranches[0]"></typelists>

P.S.

The reason console.log shows the data is because (at least in Chrome) the console "rendering" doesn't happen at the time of logging - in other words, when you call console.log the data is still not there, but it gets there before the console reads it for rendering purposes.

Sign up to request clarification or add additional context in comments.

2 Comments

ooo, I like that second concept - one of the things I'm trying to do is lazyload the tree. And if it's instantiating from the bottom up, those ng-if's will come in handy
I would actually go with the first approach - it's makes the directive more resilient to how it is being used. But, any case, did this address your question?
0

I would bet this is happening because you are setting branch.subBranches[0] in a parent directives link function.

However Angular links directives in a bottom-up manner. Namely the child directives link function will be called BEFORE the parents. Hence if you are setting 'branch.subBranches[0]' in the parent directives link function then it will still be undefined when the child directives link function is run (run first).

The timing of Angular directive DOM compilation is such that the controllers are run first from top-bottom (parent first), and then linked back up bottom-top (parent last).

So to fix your problem the easiest way would be to define/set branch.subBranches[0] in the parent's controller function (opposed to link).

EDIT:

Here is a plunker of what I suspect is happening in your case (open the console when running):

http://plnkr.co/edit/YMLAtGc38oc3vVqebH3Z?p=preview

Here is a plunker of the suggested fix:

http://plnkr.co/edit/EjrSorCvFLcDkODe2Anm?p=preview

3 Comments

Just did a quick google and found this article for you explaining it better: bennadel.com/blog/…
I'd get it if it wasn't loaded yet - what is blowing my noodle is that it shows up for 'scope' but not 'scope.branch' in the same console.log
As @NewDev mentioned we would really need to see more of your code, in particular where branch.subBranches is initialized,

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.