Angular’s one-time data binding
This week while working with AngularJS, I came across a problem where a variable within $scope being reassigned to a new value every time a function was executed. I was trying to find a solution that would prevent Angular from biding the data in the view every time the function ran, thus reassigning a new value to it. But the problem was going against what Angular stood for. Angular was all about two way data biding. Here is a solution we found.
Angular 1.3 came with tons of new features, bug fixes, improvements. One of the new features was one-time data binding. Well your first thought might be “Isn’t this Angular thing about databinding that automatically keeps the UI in sync? ”
Well, yes it is. However, Angular implementation of databinding requires the framework to keep an eye on all values that are bound. This can lead to performance issues and one-time bindings are here to help.
Understanding data-binding and watchers
In order to make databinding possible, Angular uses $watch APIs to observe model mutations on the scope. Watchers are registered through directives that are used in the DOM.
<p>Hi {{name}} !</p>
This interpolation directive registers a watch for a property name on the corresponding scope (which in our case is $rootScope) in order to interpolate against it to display the value in the DOM.
Defining a property with exactly that identifier on our scope and assigning a value to it, makes it magically displaying it in the DOM without further actions:
angular.module('myApp', [])
.run(function ($rootScope) {
$rootScope.name = "Earth";
});
We just bound a model value to the view with an interpolation directive. If now something changes the value, the view gets updated automatically.
<button ng-click="name = 'Mars'">Click me!</button>
Clicking the button assigns the string Mars to name which triggers a $digest cycle that automatically updates the DOM accordingly. Angular processes all registered watchers on the current scope and its children and checks for model mutations and calls dedicated watch listeners until the model is stabilized and no more listeners are fired. Once the $digest loop finishes the execution, the browser re-renders the DOM and reflects the changes. Due to Angulars nature of using watchers for databinding, we might get some problems in terms of performance when having too many of them.
One-time data bindings to the rescue!
This is where one-time bindings come in. The official docs says:
One-time expressions will stop recalculating once they are stable, which happens after the first.
Using this new syntax is as easy as starting an expression with :: . So if we apply the one-time expression to our example above, we change this:
<p>Hi {{name}} !</p>
Adding ” :: ” to the code, to this:
<p>Hello {{::name}}!</p>
Conclusion
This was we can use one time binding when we want angular to just bind the data one, and leave it at that. No more watcher will be used for it, and will alleviate Angular from getting bogged down with excessive watchers being used for binding.