Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>ok, I think I figured it out</p> <p>the different behavior of <code>ng-init</code> in outer/inner els arises because of the way Angular executes its compiling phase. compiling consists of different steps. the most relevant in this case are:</p> <ol> <li>controller instantiation</li> <li>prelinking</li> <li>linking</li> <li>postlinking</li> </ol> <p>that take place in this order on a per-DOMnode basis (i.e. for each node, the controller code, if present, is executed before any prelink, link, or postlink f)</p> <p><code>ng-init</code> registers a <code>pre</code>-link f on the node it is specified in, which <code>$eval</code>s the directive's content (in my example, the f assigns a value to the <code>foo</code> prop). so, when the controller code for the same node is executed, the prop does not exist yet, which is in line with @Aron's answer</p> <p>in the compile phase, Angular traverses the DOM from the root down on a depth-first basis, which means that parent els are compiled before their children. putting the <code>ng-init</code> directive in an outer el allows the controller of the child node to inherit the outer's scope. this explains the 'outer el' hack</p> <p>the hack @Aron points to registers an observer on the prop, so that, when the prop is finally <code>$eval</code>uated in the prelink phase, the callback f can find it</p> <p>I suggest two other possible hacks based on asynchronous JS and Angular features (see <a href="http://jsfiddle.net/tetotechy/Rs6D5/2/" rel="noreferrer">this jsFiddle</a>). one involves using <code>setTimeout</code> JS native f, whereas the other is more 'Angular' and resorts to <code>$evalAsync</code></p> <p>imho, there's a flaw in Angular's implementation of the <code>ng-init</code> directive with respect to the declared intent. I have hacked the Angular's code to experiment a diverse implementation. It is not difficult (2 lines of code added, even before possibly removing the <code>ng-init</code> directive native code), and works when applied to the code in the jsFiddle above, but I have not tested it on complex apps. For those interested, here is what I'm doing (refs are to v 1.2.0-rc2):</p> <ul> <li>in the <code>applyDirectivesToNode</code> f block I declare a non-initialized <code>nodeHasInitData</code> local var</li> <li>in the same f, after the local <code>directiveName</code> var is assigned the <code>directive.name</code> prop value, I test it against the <code>"ngInit"</code> static string, which is the normalized name Angular assigns to the <code>ng-init</code> directive when it is declared on the node</li> <li>if the test passes, I set the <code>nodeHasInitData</code> to <code>true</code>. nothing is done if the test fails (-> <code>nodeHasInitData</code> remains <code>undefined</code> in the closure)</li> <li>in the <code>nodeLinkFn</code> f block, before the <code>if</code> block that checks for the presence of controllers in the node (step 1 in the list above), I'm adding a test on the value of <code>nodeHasInitData</code> (I can do that because <code>nodeLinkFn</code> is defined inside <code>applyDirectivesToNode</code>)</li> <li>if the test passes, I invoke <code>scope.$eval(attrs.ngInit)</code>, which is what the prelink f of the native <code>ng-init</code> directive does. both <code>scope</code> and <code>attrs</code> are native params of <code>nodeLinkFn</code>, so they are available. nothing is done if the test fails</li> <li>this way, I have moved<sup>1</sup> the initialization from step 2 to a new step 0, which feeds the inner el scope before the corresponding controller's code is executed</li> </ul> <p><sub> 1. Actually, I have replicated it, because the prelink f defined by the <code>ng-init</code> directive is still there. It is not a great deal, however, and I think it could be easily avoided by changing/removing the directive object</sub></p> <h2>EDIT</h2> <p>To avoid replication, it is safe, for the illustrative purposes of the hack described above, to replace the assignment code of the <code>ngInitDirective</code> Angular var with <code>var ngInitDirective = valueFn({});</code></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload