【问题标题】:AngularJS not refreshing ngRepeat when updating array更新数组时AngularJS不刷新ngRepeat
【发布时间】:2013-03-12 07:45:15
【问题描述】:

有时我在理解 AngularJS 时遇到了严重的问题。所以我的控制器中有一个基本数组,比如

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

我在我的模板中对项目数组 ng-repeat="item in items" 进行 ngRepeating。到目前为止超级简单。经过几次 UX 操作后,我想将一些新内容推送到我的数组中。

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

因此,50% 的时间,新元素会添加到视图中。但剩下的 50%,什么都没有发生。这就像超级令人沮丧; bc 如果我将其包装在 $scope.$apply() 中,我会收到“$digest already in progress”错误。将其包装到 $timeout 也无济于事。

当我使用 Chrome 扩展程序检查我的元素范围时;我可以看到新数据在那里并且 $scope.items 值是正确的。但视图只是不负责将其添加到 DOM。

谢谢!

【问题讨论】:

  • 你能在jsfiddle.net创建一个演示吗
  • 它肯定与摘要周期有关。我们需要您发布用于更新数组的代码。
  • 我也遇到了这个问题,希望得到答案!

标签: javascript angularjs angularjs-ng-repeat


【解决方案1】:

您正在修改 Angular 的 $digest 周期之外的范围 50% 的时间。

如果有一个不是来自 angularjs 的回调; (可能是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);
}

【讨论】:

  • 我相信你应该避免检查$scope.$$phase。它是内部变量,如果可能的话,你不应该依赖这些代码。最好的解决方案是使用$apply,您绝对确定没有$apply 已经在进行中。这就是为什么我要求提供可能更新范围的代码。
  • 这不是一个好的编码方式,我同意。然而,它确实有效,$$phase 非常一致和可靠;至少它不会意外破坏你的代码,除了它可以在版本之间更改。
  • 是的。我确实已经用过了。问题是我们不知道这是否会在下一个小版本中中断,因为它的内部状态控制器。我只是在思考可能有更好的地方来安全地放置$apply
  • “它是”是指可靠性部分。我们同意这不是一个好的做法。只是为了确定:)
【解决方案2】:

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

# 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 的人的问题。

【讨论】:

    【解决方案3】:

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

    此问题的主要原因是您的函数被调用作为对 DOM 事件的反应。例如

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

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

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

    但是,您必须注意一个警告:当您从代码中触发点击事件时,您会遇到摘要循环已经在进行中的问题。这是您需要 $timeout 的地方。 this question 的答案很好地涵盖了这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-12
      • 1970-01-01
      • 2017-06-29
      相关资源
      最近更新 更多