如何从控制器内推送到由ng-repeat迭代的数组?

时间:2015-10-01 14:42:28

标签: angularjs controller ng-repeat

这是Angular的行为我不知道。

假设我在控制器中有一系列项目,并在视图中重复它们。我在视图中有一个按钮,当我点击它时,一个项目被推入数组中。 ng重复列表在视图中更新。到目前为止一切都很好。

但是 如果我只是在控制器内的数组中推送一个新项(比方说,我设置了一个超时),视图中的ng-repeat将不会注册数组的更改。

关于plunker的例子:http://plnkr.co/edit/1mlOpGVOXmnCAa8W5KEx?p=preview

HTML:

<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.0-beta.4/angular.min.js"></script>
    <script src="script.js"></script>
  </head>

  <body ng-app="myApp">
    <main ng-controller="MainController as ctrl">
      <button ng-click="ctrl.addName()">Add an item</button>
      <ul>
        <li ng-repeat="name in ctrl.names">
          {{name.name}}
        </li>
      </ul>
    </main>
  </body>

</html>

JS:

angular.module('myApp', [])
  .controller('MainController', function(){
    var self = this;

    self.test = 2;
    self.names = [{name: 'example'}];

    self.addName = function(){
      self.names.push({name: 'new example'});
      console.log(self.names)
    };

    setTimeout(function(){
      self.names.push({name: 'another example'});
      console.log(self.names);
    }, 1000);

  });

观察到的行为:单击该按钮将触发addName功能并将项目添加到列表中。但是setTimeout会推送数组中的项目,但这不会反映在视图中。在检查控制台日志的结果时,我看到显示的项目具有$$hashKey属性,并且对数组的简单推送将导致缺少此属性的项目。

问题:在控制器中向项目添加项目的正确方法是什么?我应该使用$ digest还是$ apply或者什么?

1 个答案:

答案 0 :(得分:3)

如果任何观察的模型值发生变化,Angular会定期执行脏检查。它在所谓的$digest周期中这样做。当Angular认为有必要时会自动运行这些循环,但如果事件发生在Angular上下文之外,Angular将不会知道它,不会触发$digest周期,也不会检测到更改和视图不会更新。

当您将值推送到数组(在Angular上下文之外)时,您需要手动运行$ digest循环,例如通过将函数包装到$scope.evalAsync()中,这将触发范围内的脏检查。

更新:是的,你也可以拨打$scope.$digest(),但问题是如果$ digest周期已经开始运行,你将会得到那个不可思议的“$ digest ()已在进行中“错误。

$scope.evalAsync()不会遇到这个问题,因为它会异步触发$digest个循环。更重要的是,如果$digest周期已在进行中,它将尝试在同一周期内完成工作,并且不会不必要地启动新工作。

Ben Nadel也可以看到这个excellent blog post,更详细地解释所有内容(例如,使用$timeout服务进行比较,这是另一种选择)。