Trying to use $interval from angular to change the currently visible item in a list using ng-show. Inspecting the html, I noticed that angular changes ng-show from true/false, but it doesn't remove the ng-hide class.
The html is simple:
<h1>Hello Plunker!</h1>
<div ng-controller="MyCtrl">
<div>Iterator: {{i}}</div>
<ul>
<li ng-repeat="d in data" ng-show="{{i == $index}}">{{i}} - {{$index}} - {{d}}</li>
</ul>
</div>
The app.js is quite basic as well:
(function(){
var app = angular.module('MyApp', ['my-controller']);
})();
and my module/controller
(function(){
var app = angular.module('my-controller', []);
app.controller('MyCtrl', ['$scope', '$interval', function($scope, $interval){
$scope.data = [111, 222, 333, 444];
$scope.i = 0;
var timeoutId;
timeoutId = $interval(function(){
$scope.i ++;
if ($scope.i >= $scope.data.length)
$scope.i = 0;
},
1000);
}]);
})();
Here's my plnkr
That is because you are setting the string "true"/"false" by using interpolation ({{i == $index}}
) in the ng-show expression, instead just provide the expression directly.
ng-show="i == $index"
Plnkr
Just to add explanation, have a look at the ng-show source code
scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
// we're adding a temporary, animation-specific class for ng-hide since this way
// we can control when the element is actually displayed on screen without having
// to have a global/greedy CSS selector that breaks when other animations are run.
// Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
$animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
tempClasses: NG_HIDE_IN_PROGRESS_CLASS
});
});
It registers a watch on the attribute value, so when using interpolation (which renders first) so it actually sets watch on "true"
for the first item and "false"
for the last three (As expected). All is well and the watch runs for the first time for dirty checking and it gets parsed to boolean value and it adds ng-hide class to the last 3 and first one remains displayed. So till now watch is set on the string "true/false" on the scope and it is never going to change and watch no longer executes (since it always will return same value during the digest cycle triggered by timeout in your case) and items shows remains shown and hidden remains hidden as it never gets a chance to execute add/removeClass
. Now when you use an expression it will get evaluated every time digest happens, boolean flag evaluated as value of the expression changes and watcher gets executed and class gets added/removed as intended.