31

有时我在理解 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 中。

谢谢!

4

3 回答 3

21

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

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

您需要知道回调何时不是来自角度的,并且应该$apply只在那时调用。

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

var applyFn = function () {
    $scope.someProp = "123";
};
if ($scope.$$phase) { // most of the time it is "$digest"
    applyFn();
} else {
    $scope.$apply(applyFn);
}
于 2013-03-22T13:15:30.247 回答
4

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

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

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

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

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

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

于 2015-07-22T06:32:37.340 回答
0

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

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

于 2013-11-25T20:21:26.593 回答