![]()
One-time binding (::) is a feature in AngularJS 1.3+ that improves performance by binding data only once, instead of continuously watching for changes. However, sometimes it does not work as expected, leading to missing or outdated data in the UI.
In this guide, we’ll explore:
How one-time binding works.
Why it might not work properly.
Solutions to fix issues with ::.
1. How One-Time Binding (::) Works in AngularJS?
In regular AngularJS bindings ({{ expression }}), the value updates every time a digest cycle runs. This means Angular continuously watches for changes, which can slow down performance in large applications.
With one-time binding (::), Angular only evaluates the expression once and stops watching it. This reduces the number of watchers, improving performance.
Example: Regular vs. One-Time Binding
<p>Regular Binding: {{ user.name }}</p>
<p>One-Time Binding: {{ ::user.name }}</p>
Regular binding ({{ user.name }}) updates whenever user.name changes.
One-time binding ({{ ::user.name }}) only updates once when user.name is first defined and then stops.
2. Why One-Time Binding (::) Might Not Work?
Data Not Available Initially (Undefined Value)
Problem: One-time binding only works if the data is available when Angular evaluates it. If the data is loaded asynchronously (e.g., from an API or $http request), it won’t appear.
Bad Example: Data Not Ready at Load Time
<p>User Name: {{ ::user.name }}</p>
$scope.user = {}; // Initially empty
setTimeout(() => {
$scope.user.name = "John Doe"; // Updates after delay
}, 2000);
Issue: Since user.name is undefined when the view loads, AngularJS does not bind it, and even when the value updates later, the UI does not change.
Solution: Use ng-if or ng-show
<p ng-if="user.name">User Name: {{ ::user.name }}</p>
ng-if="user.name" ensures the element only appears when data is ready.
One-Time Binding on Computed Properties
Problem: If you use a computed value (e.g., a function call inside ::), Angular does not track the function’s return value after the first call.
Bad Example: One-Time Binding on a Function
<p>Full Name: {{ ::getFullName() }}</p>
$scope.getFullName = function () {
return $scope.firstName + " " + $scope.lastName;
};
setTimeout(() => {
$scope.firstName = "John";
$scope.lastName = "Doe";
}, 2000);
Issue: getFullName() is only called once. If firstName and lastName update later, the UI won’t refresh.
Solution: Store Computed Value in a Variable
$scope.user = {};
$scope.user.fullName = $scope.firstName + " " + $scope.lastName;
<p>Full Name: {{ ::user.fullName }}</p>
Now, Angular binds to user.fullName instead of calling a function.
One-Time Binding in ng-repeat Not Updating
Problem: When using :: inside an ng-repeat, Angular only binds data once per item. If the list is loaded asynchronously, no updates appear.
Bad Example: :: in ng-repeat
<ul>
<li ng-repeat="user in ::users">{{ user.name }}</li>
</ul>
$scope.users = [];
setTimeout(() => {
$scope.users = [{ name: "Alice" }, { name: "Bob" }];
}, 3000);
Issue: Since users was empty when Angular first evaluated ::users, ng-repeat does not update when data arrives.
Solution: Use ng-if or Assign Data in Controller
<ul ng-if="users.length">
<li ng-repeat="user in users">{{ ::user.name }}</li>
</ul>
$scope.users = [];
setTimeout(() => {
$scope.users = [{ name: "Alice" }, { name: "Bob" }];
$scope.$apply(); // Manually trigger digest
}, 3000);
ng-if="users.length" prevents evaluation until data is ready.
$scope.$apply(); ensures Angular detects the update.
One-Time Binding on Watchers ($watch Not Triggering Updates)
Problem: If you use one-time binding on a variable inside $watch, the watcher never fires again.
Bad Example: Using :: in $watch
$scope.$watch('::user.name', function (newValue) {
console.log("User name changed:", newValue);
});
Issue: $watch does not track ::user.name because one-time bindings are removed from the digest cycle.
Solution: Use Regular Watch Instead
$scope.$watch('user.name', function (newValue) { console.log("User name changed:", newValue); });$watch('user.name')ensures changes are detected normally.
3. Best Practices for One-Time Binding (::)
Use :: only on static values (e.g., labels, titles).
Use ng-if or ng-show to wait for data before binding.
Avoid :: in computed expressions (use precomputed variables instead).
Don’t use :: inside $watch, as it disables tracking.
For large lists, assign data first, then use ng-repeat without ::.
