Context
The issue does not lie with the ng-repeats in this code snippet. Instead, the focus should be on understanding the interpolated expression: {{dateBasedFunction(j.data)}}
Angular sets up a watcher to monitor changes in the expression dateBasedFunction(j.data)
during each iteration of the digest cycle. If there's a change in the resulting value since the last digest, the DOM will reflect this update.
The challenge lies in the absence of any triggers in your code that initiate an Angular digest cycle.
Solution Example
Demonstrating functionality by manually triggering a digest through user interaction:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', ['$scope', MyCtrl]);
function MyCtrl($scope) {
$scope.rootArray = [{
"array1": [{
"array2": [{
"data": "hello"
}, {
"data": "world"
}]
}]
}];
//Dummy $watch displays a message whenever digest is called
$scope.$watch(function() {
console.log('Digest called');
});
$scope.dateBasedFunction = function(x) {
var d = new Date();
return x + ' (' + d.getMinutes() + ":" + d.getSeconds() + ")";
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<button ng-click="">ng-click calls digest()</button>
<div ng-repeat="i in rootArray">
<div ng-repeat="h in i.array1">
<div ng-repeat="j in h.array2">
<span>{{dateBasedFunction(j.data)}}</span>
</div>
</div>
</div>
</div>
</div>
By clicking the button, ng-click
initiates an Angular digest. This re-evaluates dateBasedFunction
, prompting a DOM refresh due to the changed value.
If continuous updates are desired without relying on manual clicks, alternative solutions can be considered for updating the DOM periodically based on real-time data changes.
Potential Approaches
- Choose a suitable update frequency and implement periodic digestion:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', ['$scope', MyCtrl]);
function MyCtrl($scope) {
$scope.rootArray = [{
"array1": [{
"array2": [{
"data": "hello"
}, {
"data": "world"
}]
}]
}];
//Dummy $watch alerts whenever digest is called
$scope.$watch(function() {
console.log('Digest called');
});
$scope.dateBasedFunction = function(x) {
var d = new Date();
return x + ' (' + d.getMinutes() + ":" + d.getSeconds() + ")";
}
//Invoke $scope.$apply() every second.
setInterval(function() {
//$scope.$apply() triggers a digest cycle
$scope.$apply();
}, 1000);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div ng-repeat="i in rootArray">
<div ng-repeat="h in i.array1">
<div ng-repeat="j in h.array2">
<span>{{dateBasedFunction(j.data)}}</span>
</div>
</div>
</div>
</div>
</div>
Create a directive for targeted updates based on known intervals, avoiding scope-wide application calls for efficiency at the cost of additional development effort.
A project like angular-moment illustrates this idea through the am-time-ago
directive, specializing in managing dynamic content tied to current dates or times.
Maintain watch on model changes via Angular but handle date/time adjustments externally:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', ['$scope', MyCtrl]);
function MyCtrl($scope) {
$scope.rootArray = [{
"array1": [{
"array2": [{
"data": "hello"
}, {
"data": "world"
}]
}]
}];
//Dummy $watch alerts whenever digest is called
$scope.$watch(function() {
console.log('Digest called');
});
}
function dateBasedFunction(x) {
var d = new Date();
return x + ' (' + d.getMinutes() + ":" + d.getSeconds() + ")";
}
setInterval(function() {
$('[data-date-based-value]').each(function() {
this.textContent = dateBasedFunction(this.dataset['dateBasedValue']);
});
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div ng-repeat="i in rootArray">
<div ng-repeat="h in i.array1">
<div ng-repeat="j in h.array2">
<!--Set a data-date-based-value attribute-->
<!--Angular will keep the attribute value updated-->
<!--But the element's text will be updated via jQuery-->
<span ng-attr-data-date-based-value="{{j.data}}"></span>
</div>
</div>
</div>
</div>
</div>
This approach directly updates the DOM, bypassing extra digest cycles for efficient rendering.
For further insights into Angular's digest cycle, consider exploring this article.