Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h2>Underlying Issue</h2> <p>As a lead in its helpful to look at '&amp;' which the <a href="http://code.angularjs.org/1.0.8/docs/guide/directive" rel="noreferrer">docs</a> describe this way:</p> <blockquote> <p>&amp; or &amp;attr - provides a way to execute an expression in the context of the parent scope.</p> <p>Often it's desirable to pass data from the isolated scope via an expression and to the parent scope, this can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22})</p> </blockquote> <p>In order to achieve this the function that is passed through an <code>&amp;</code> is wrapped in another function <code>parentGet()</code>. We can see this in action by looking at the contents of the click handler function variable. First, before it's passed into the <code>&amp;</code> it's as we'd expect:</p> <pre><code>function (node) { console.log("called with ",node); } </code></pre> <p>But, then, inside your directive, after passing through '&amp;', it looks like this:</p> <pre><code>function (locals) { return parentGet(scope, locals); } </code></pre> <p><strong>So instead of a direct reference to your click handler function it is now a call that will apply your function using both the parent scope and any <code>locals</code> which you pass in</strong>.</p> <p>The problem is that, from what I can tell, <strong>as we nest down that scope variable keeps getting updated</strong> to the new nested parent scope. That's not good for us. We want the execution context to be that top scope where your click handler is. Otherwise we lose reference to your function- as we see happening.</p> <h2>Solution</h2> <p><strong>To fix this we keep a reference to the original function</strong> (that isn't encumbered by <code>parentGet()</code> as we nest down). Then when we pass it in, the scope used in <code>parentGet()</code> is the one with click handler function on it.</p> <p>First let's use a different name for the actual function than you'll use for the parameter. I set up the function like so <code>$scope.onNodeClickFn = function(node) {...}</code> </p> <p>Then we make 3 changes:</p> <p><strong>1)</strong> Add a second scope variable (<code>topFunc</code>):</p> <pre><code>scope: { onNodeClick: '&amp;', topFunc: '=' } </code></pre> <p><code>onNodeClick</code> is the wrapped function (including scope parameter). And <code>topFunc</code> is a reference to the unwrapped function (note that we pass that in using <code>=</code> so it's a reference to the function absent the wrapper that <code>&amp;</code> applies).</p> <p><strong>2)</strong> At the top level, we pass both function references in. </p> <pre><code>&lt;recursive-list-item on-node-click="onNodeClickFn(node)" top-func="onNodeClickFn" parent=parent &gt;&lt;/recursive-list-item&gt; </code></pre> <p>(note the lack of () on the <code>top-func</code> parameter.)</p> <p><strong>3)</strong> Pass the new <code>topFunc</code> parameter in to the template:</p> <pre><code>&lt;recursive-list-item data-parent="child" data-on-node-click="topFunc(node)" top-func="topFunc"&gt;&lt;/recursive-list-item&gt; \ </code></pre> <p><strong>So we are now maintaining a reference, at each nested scope, to the original function and using that in the template</strong>.</p> <p>You can see it working in this fiddle: <a href="http://jsfiddle.net/uf6Dn/9/" rel="noreferrer">http://jsfiddle.net/uf6Dn/9/</a></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.
    3. VO
      singulars
      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