4

I'm creating some directives with an isolated scope and some aliased properties. For example:

scope: {
   prop1: '@'
}

My question is, when exactly to these aliases get added to the scope? I was running into some issues with the properties not being defined in my link function. Look in the console after running this jsFiddle: http://jsfiddle.net/rvd6x/.

When I try to get the property as normal it is not defined. If I try to get it later through a function (doStuff()) it is there. Or if I do a $timeout with 0 it is there. Obviously I can workaround my issues by using the $timeout, but I want to know why I can't just expect the scope to already have it right away in the link function. It'd be kind of a pain to have to inject $timeout throughout all my directives.

dnc253
  • 39,967
  • 41
  • 141
  • 157

2 Answers2

4

I found that this works inside the directive definition:

scope: {
    prop1: '@'
},
link: function(scope, element, attrs) {
    ...
    attrs.$observe('prop1', function(val) { 
        scope.prop1 = val || 'default'
    });
    ...
}

to make

<div my-directive></div>

behave like

<div my-directive prop1="default"></div>
grumplet
  • 285
  • 2
  • 14
  • Having much more experience with Angular now, this is definitely the correct answer. Info about `$observe` can be found here: http://docs.angularjs.org/guide/directive#Attributes. Updated fiddle: http://jsfiddle.net/rvd6x/5/ – dnc253 Mar 19 '13 at 05:45
1

Here's my understanding: In general in a directive, you can not assume that any variable in a scope is defined or has a stable value. You need to $watch anything that's of interest to you.

Think of ng-repeat - the thing that you're repeating on might not exist at link time, it might change often, etc. - it's up to the directive to handle those scenarios.

Now I know that doesn't answer your question - you're creating an isolated scope which is explicitly setting a scope value, so intuitively what you're doing is different than the ng-repeat example. But it looks like Angular treats them the same and this is probably a good thing.

Depending on what you need to use the attribute for I think you can solve your problem in two ways:

  1. If it's an evaluated value and it might change, wrap it in a watch so you can react.
  2. If it's a static value you can use attrs.prop1 and pull it down at the beginning of your link fn.

Both of these options I've added to the fiddle here.

Roy Truelove
  • 22,016
  • 18
  • 111
  • 153
  • Thanks for the info. In my case I have several layers of directives, with a static value that gets passed down through the layers. I originally was using the attrs parameter in the link function, but then found that the link function for my inner directive was being called before the link function of the outer most directive, so the outer directive didn't have a chance to set the value into the scope and pass it along (I hope that makes sense). Even though it is a static value, I may try using the $watch, and see if that gets me what I need. I'll post my results. – dnc253 Oct 01 '12 at 14:55
  • In that case the value for inner directive is transitive and would probably be better served with a $watch. Oh the joys of asynchronous programming! – Roy Truelove Oct 01 '12 at 15:50
  • Yeah, I'm pretty new to asynchronous programming and have quickly found many of those joys. :) It looks like the $watch is going to work for me. Thanks for the help. – dnc253 Oct 02 '12 at 15:16