patrick patrick - 1 month ago 16
AngularJS Question

one-time binding with ng-if in angular?

If I have a view that does:

<div ng-repeat="foo in foos">
<p ng-if="bar">omg lol</p>
<p ng-if="!bar">lol omg</p>
</div>


I am actually creating (2 * foos.length) + 1 $$watchers, which is really not good. I have found several sources online that say you can do ng-if="::bar", but the number of watchers does not change when I do that. Is there a way to force ng-if to be a one time binding?

It is really, really dumb to have to do:

<div ng-repeat="foo in foos" ng-if="bar">
<p>omg lol</p>
</div>
<div ng-repeat="foo in foos" ng-if="!bar">
<p>lol omg</p>
</div>


Which I believe will give me something like 4 $$watchers instead... So I am looking for an alternative to avoid having to be silly like that.

PSL PSL
Answer

Just extending my comments to answer.

Angular 1.3 one-time binding syntax (::) indeed will remove unnecessary watches. Just that you need to measure the watches a while after you set the relevant data. Here is why it is. When you set a one-time bound property on the view, angular will set a temporary watch on it until it gets a defined value, i.e anything but undefined. This approach is there for a reason - in order to support the bound values that are populated via a deferred operation like ajax call, timeout, promise chain resolution etc.. Without this :: will not work successfully on anything but pre-populated bound values.

So just make sure that you set some value at some point in time to the one-time bound values. Don't let it remain undefined.

Say when you have a condition <div ng-if="::lol"></div> repeated 100 times. Just make sure when you bind the value to the repeater or some operation that determines the status of lol even if that operation fails (say a ajax call error) still set a value (even null is also a value in javascript) to it. Watches will be removed after the upcoming digest cycle which renders the respective DOM bindings.

In your specific plunker you could as well do:

<ul ng-repeat="item in items"  ng-if="::lol">
  <li>{{ ::item }}</li>
</ul>

instead of

<ul ng-repeat="item in items">
  <li ng-if="::lol">{{ ::item }}</li>
</ul>