Reputation: 8149
If I modify $scope after a $timeout, my view doesn't get rendered properly. I don't understand why. It works if I don't do the $timeout first.
http://plnkr.co/edit/oGuPgt7VaYKgPFh00lDV?p=preview
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js'></script>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script>
angular.module('treeApp', [])
.controller('TreeController', ['$scope', '$timeout', function($scope, $timeout) {
// This works
// $scope.nodes = {
// 1:{node_id:1, text:'foo text', parent_id:null, child_ids:[2,3]},
// 2:{node_id:2, text:'bar text', parent_id:1, child_ids:[]},
// 3:{node_id:3, text:'abc text', parent_id:1, child_ids:[]}
// }
// $scope.top_ids = [1]
// This doesn't work
$timeout(function() {
$scope.nodes = {
1:{node_id:1, text:'foo text', parent_id:null, child_ids:[2,3]},
2:{node_id:2, text:'bar text', parent_id:1, child_ids:[]},
3:{node_id:3, text:'red text', parent_id:1, child_ids:[]}
}
$scope.top_ids = [1]
}, 1000)
}])
</script>
<div ng-app="treeApp">
<script type="text/ng-template" id="node.html">
<li node_id="{{node_id}}" ng-repeat="node_id in node_ids" ui-tree-node
ng-init="node = nodes[node_id]">
{{node.text}}
<ol ng-include="'node.html'" ng-init="node_ids = node.child_ids"></ol>
</li>
</script>
<div ng-controller="TreeController">
<ol ng-include="'node.html'" ng-init="node_ids = top_ids"></ol>
<pre>{{top_ids | json}}</pre>
<pre>{{nodes | json}}</pre>
</div>
</div>
Upvotes: 1
Views: 77
Reputation: 26848
<ol ng-include="'node.html'" ng-init="node_ids = top_ids"></ol>
You initialize node_ids
with top_ids
. It's a one-time assignment, not a binding. When you use $timeout
the value of top_ids
is undefined
at the point of the assignment.
The easiest solution is to rename $scope.top_ids
to $scope.node_ids
and get rid of ng-init
.
Upvotes: 1
Reputation: 21901
use $scope.$apply();
like below
$timeout(function() {
$scope.nodes = {
1:{node_id:1, text:'foo text', parent_id:null, child_ids:[2,3]},
2:{node_id:2, text:'bar text', parent_id:1, child_ids:[]},
3:{node_id:3, text:'abc text', parent_id:1, child_ids:[]}
}
$scope.top_ids = [1];
$scope.$apply();
}, 1000)
or you can wrap model changes like below,
$timeout(function() {
$scope.$apply(function () {
$scope.nodes = {
1:{node_id:1, text:'foo text', parent_id:null, child_ids:[2,3]},
2:{node_id:2, text:'bar text', parent_id:1, child_ids:[]},
3:{node_id:3, text:'abc text', parent_id:1, child_ids:[]}
}
$scope.top_ids = [1];
});
}, 1000)
here is a good demo,
Here is the working plunker
if you change any model outside of the Angular context, then you need to inform Angular of the changes by calling $apply() manually..... For example, if you use JavaScript’s setTimeout() function to update a scope model, Angular has no way of knowing what you might change. In this case it’s your responsibility to call $apply() manually
Upvotes: 0