1

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>
3
  • try assigning your $scope to a variable and use that variable inside the timeout or maybe provide a fiddle Commented Nov 10, 2014 at 8:33
  • I tried assigning $scope to a variable but it didn't fix the problem. I did provide a plunkr (see the link right above the code). Commented Nov 10, 2014 at 8:37
  • Never use ng-init unless you need to save outer index in nested ng-repeat. Commented Nov 10, 2014 at 8:50

2 Answers 2

1
<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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

2 Comments

This doesn't solve the problem. I'm pretty sure $timeout automatically calls $apply.
That plunkr is not working. There is supposed to be a tree rendered above the raw json. Uncomment the commented code in order to see it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.