AngularJS在更新数组时不刷新ngRepeat

AngularJS not refreshing ngRepeat when updating array

本文关键字:刷新 ngRepeat 数组 更新 AngularJS      更新时间:2023-09-26

有时候我很难理解AngularJS。控制器中有一个基本数组,比如

$scope.items = ["a","b","c"]

我在我的模板中复制项目数组ng-repeat="item in items"。到目前为止非常简单。在几个UX操作之后,我想把一些新东西推到我的数组中。

 $scope.items.push("something");

因此,50%的时间,新元素被添加到视图中。但剩下的50%,什么都没发生。这就像超级令人沮丧;如果我把它包装在$scope.$apply()中,我得到一个"$digest already in progress"的错误。将其封装到$timeout中也没有帮助。

当我检查我的元素范围使用Chrome扩展;我可以看到这里有新的数据和$作用域。"Items"值是否正确。但是视图并没有把它添加到DOM中。

谢谢!

你在50%的时间里在angular的$digest循环之外修改作用域。

如果有一个不是来自angularjs的回调;(posibbly jquery)。你需要调用$apply来强制$digest循环。但是你不能在$digest循环中调用$apply,因为你所做的每一个更改都会自动反映出来。

你需要知道什么时候回调不是来自angular,应该只调用$apply

如果你不知道也无法学习,这里有一个巧妙的技巧:

var applyFn = function () {
    $scope.someProp = "123";
};
if ($scope.$$phase) { // most of the time it is "$digest"
    applyFn();
} else {
    $scope.$apply(applyFn);
}

正如Umur kontacyi所指出的,您有时会在摘要周期之外进行模型更改。但是,与其解决这个问题并试图检测您是否处于应用/摘要上下文中,我建议您确保这种情况永远不会发生。

这个问题的主要原因是您的函数是作为对DOM事件的响应而调用的。例如

jQuery('.some-element').click(function() { seeminglyProblematicCode() })

这是你的$apply()需要去的地方,而不是在函数中。否则,您的整个代码迟早会充斥着这样的区别。假设在这个事件处理程序的上下文中有一个作用域,您可以这样写:

jQuery('.some-element').click(function() { 
    $scope.$apply(function() { seeminglyProblematicCode() })
})

然而,有一点需要注意:当您从代码中触发click事件时,您将遇到一个问题,即摘要循环已经在进行中。这就是需要使用$timeout的地方。这个问题的答案很好地涵盖了这个问题。

我也遇到了同样的问题,我的修复方法是观察在嵌套指令中调用了哪些控制器。

# Parent Controller
app.controller 'storeController', ($scope, products) ->
  $scope.cart = ["chicken", "pizza"]
  $scope.addToCart = (item) ->
    $scope.cart.push item
  # from service
  products.get().then (items) ->
    $scope.products = items
# Parent Directives
app.directive 'storeContainer', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-container.html'
  controller: 'storeController'
# Nested Directive
app.directive 'storeFront', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-front.html'
  controller: 'storeController'
# Parent Template templates/directives/store-container.html
<div ng-repeat="item in cart">{{ item }}</div>
<strore-front></store-front>
# Nested Template templates/directives/store-front.html
<ul ng-repeat="item in products">
  <li ng-click"addToCart(item)">{{ item }}</li>
</ul>

这里的错误是嵌套指令在原型链中创建了第二个控制器(storeController的副本),父模板无法访问它。要解决像这样编写嵌套控制器的问题:

# Nested Directive
app.directive 'storeFront', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-front.html'

有更好的方法来创建继承链,但这将解决许多学习AngularJS的人的问题。