30

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.

11
  • :: is one time binding. Just that it wil have a temporary watch created initially and then removed once value is assigned to the bound property. Do you have a proof plunker? Commented Jun 18, 2015 at 0:03
  • 1
    Yes, here is a plunker showing that 2 seconds after the dom has been rendered, the $$watcher count is 2000 just from an ng-if... plnkr.co/edit/JgP3lRyuSoSPQNIgR8Ri?p=preview Commented Jun 18, 2015 at 0:46
  • 2
    What i see is <li ng-if="::lol">{{ ::item }}</li> watcher count ==> 2 without prefixing lol with :: it is 1002. What say you? Commented Jun 18, 2015 at 0:47
  • totally confused... what? so you are saying the alert window pops up after the timeout on your browser says 2 watchers? Commented Jun 18, 2015 at 0:51
  • 1
    I apologize, I thought I had saved the version with ::lol, not just lol. Well, this is very odd because this is not the behavior I am experiencing with my app, the :: prefixes in my ng-ifs are doing absolutely nothing and my watcher count is in the thousands, so I think I need to investigate further. Commented Jun 18, 2015 at 0:54

2 Answers 2

37

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>
Sign up to request clarification or add additional context in comments.

Comments

0

You need to use Bindeonce to do this : https://github.com/Pasvaz/bindonce

2 Comments

Not since Angularjs 1.3 that natively supports one time bindings using the :: syntax
@mxa055 did you read my question? ng-if="::foo" does nothing. It still creates gazillions of watchers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.