Search code examples
javascriptangularjsangular-directive

One-time binding along with directive's bidirectional binding and ng-repeat


Say we have the following directive:

app.directive('foo', function() {
  return {
    restrict: 'E',
    scope: { prop: '=' },
    template: '<h1>{{prop}}</h1>'
  };
});

Angular documentation says it's possible to use an one-time binding along with a bidirectional binding, like this:

<foo prop="::someProperty"></foo>

And it works; if someProperty later changes, the foo directive won't know about it.

Now consider this markup:

<foo ng-repeat="item in items" prop="::item"></foo>

In this case, if item later changes, foo will be notified, as if there's a regular binding in place. The :: doesn't seem to have any practical effect (it does prevent an extra watch from being created, I checked myself). I created this plunker that illustrates both cases.

My question is: is that behavior correct? I would expect it to be consistent in both scenarios.


Solution

  • I believe the answer to your question is yes, this is the correct behavior. When an item within items changes, a new instance of the template is created while the old is simply removed. In your case, a new foo element is created and therefore, the prop attribute value is also new. This is from the Angular ngRepeat documentation:

    When the contents of the collection change, ngRepeat makes the corresponding changes to the DOM:

    • When an item is added, a new instance of the template is added to the DOM.
    • When an item is removed, its template instance is removed from the DOM.
    • When items are reordered, their respective templates are reordered in the DOM.

    It doesn't explicitly state what happens on update. But, I believe the new replaces the old rather than update.