This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

New in Angular 1.3 - Bind Once

5:33 Angular 1.x lesson by

AngularJS's two-way binding is one of the "killer features" of the framework. The problem is that too many bindings can cause performance issues! Many times, all you need to do is bind a single time to get the data to display, and don't need dynamic two-way binding. In Angular 1.3, they've added new syntax to enable one-time data bindings.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

AngularJS's two-way binding is one of the "killer features" of the framework. The problem is that too many bindings can cause performance issues! Many times, all you need to do is bind a single time to get the data to display, and don't need dynamic two-way binding. In Angular 1.3, they've added new syntax to enable one-time data bindings.

Avatar
Bilal

$scope.$watch('::people') doesn't work as people is on the view model vm not the scope.

Previously i've had to do the following to get watchers to work on the vm
$scope.$watch(function () {
return vm.people;
}, function (val) {}))

But as the vm.people is not a string in this case, i'm not sure how to use the '::' prefix

Thanks for your help!

In reply to egghead.io

This is another video about the cool things coming in, Angular 1.3, and we're on RC3, the latest release candidate for 1.3. Hopefully, it'll be really soon. We're going to be talking about one-time bindings in Angular 1.3.

Here, we have a very simple example application. It's just a big, long list of users with some information about them. We can control how many people show up -- zero, then, one, two, et cetera, up to a 100. We're also keeping track of our watch count.

You can see, as I increase this, each one of these cards has 20 watchers on it. Between the image, this is a watcher here, all of the information here that adds up to 20 watchers per card.

If we bring ourselves to 10, we have 205 watchers. Not totally unreasonable, that's totally fine, especially with something so simple, but as an application grows, the watch count grows.

Ultimately, what's really important is that digest cycle starts to take a little longer. Anything over 16 milliseconds per digest cycle will result in losing that 60 frames per second that we're going after. The code to do this is actually very simple.

We just have this "visible people" that's bound there. We have this increment, because as we click on this person we're incrementing, how many times we're clicking on them, and then we create the people.

We create a 100 fake people, we're using the Faker library, we create a card, and then we also create their avatar. Then, we push that to VM people and then we have an ng-repeat here. I'm going to hide the JavaScript, we don't need that any more. We'll show the HTML.

To do one-time bindings, it's actually very easy. It's just a new syntax to your expressions. All that you need to do is add a double-colon before the expression in your template. That is now bound one time.

If you notice here, we'll go down to zero. If we go up one, that's adding 19 instead of 20, as it was before.

This is no longer being watched. Basically, what this means is, I'm telling Angular, this is a one-time bound expression. I only want you to evaluate this in a digest cycle until it becomes defined. Once it becomes defined, don't watch it any more, don't update the DOM for this particular watcher.

We can do that for all of these. Let's just really quickly go through and replace all of those bindings. We'll replace this one, that one, we'll go through and replace all of these, and see what this does to our watch count.

Great, now, we have 10 total people and only 15 watchers. Looks like I must have missed a watcher in here somewhere.

Here we go, the picture. Now, we have five watchers and that's for the ng-repeat and different things. As we increase the number of people or decrease, you notice there's not a change in our watch count.

That's awesome, that's way cool, cool stuff for our application performance, but it does come with a couple of trade-offs.

If you remember every time I click on a user's profile, this number will increment. If I click on them now, the number is technically still incrementing on the model, but it's not getting updated here, because this is a one-time bound expression.

Let's go ahead and make it a simple, regular, evaluated expression. Now, our watch count is up to 15, because we have one watcher per person for this item here.

Now, as I click, that gets updated. There are couple of places where you can't really use bind once. There are some more grounds to that, for the main use case.

You're going to want to make sure that anywhere that you know will change eventually, and you want that to be bound, you want to make sure that you don't do a bind once for that, obviously.

One example of that, just really quick is we have some cool binding here. If I were to say, "Hey, I want you to bind that once," and we'll go back to zero here.

Cool, but that's actually not very cool, because now, I've lost that binding. You do need to be a little bit careful about how you're using bind once, but it's definitely a cool feature in Angular.

It actually impacts anything that runs through Angular's parser. You can use this in your watch expressions, as well. You can say "scope.watch" and prefix it with a double-colon.

Angular will treat this as a singly bound expression. You could say "watchPeople," and now, people will be watched only until it becomes defined. Then, that watcher will stop running. Any valid expression can be prefixed with the double-colon.

This is a great performance boost for applications and I have already found some good use, as I've been using the release candidates and the betas for 1.3. Hopefully, you can find some good use for it, too.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?