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.
ng-if is better in this regard. Using it in place of ng-show will prevent the heavy content from being rendered in the first place if the expression is false. However, its strength is also its weakness, because if the user hides the chart and then shows it again, the content is rendered from scratch each time.
Definition and Usage The ng-if directive removes the HTML element if the expression evaluates to false. If the if statement evaluates to true, a copy of the Element is added in the DOM.
ng-if can only render data whenever the condition is true. It doesn't have any rendered data until the condition is true. ng-show can show and hide the rendered data, that is, it always kept the rendered data and show or hide on the basis of that directives.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With