When do isolated scope properties actually get added to the scope?

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.

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>

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.