最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - AngularJS not refreshing ngRepeat when updating array - Stack Overflow

programmeradmin1浏览0评论

I'm having serious troubles understanding AngularJS sometimes. So I have a basic array in my controller like

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

I'm ngRepeating in my template over the items array ng-repeat="item in items". Super straightfoward so far. After a couple of UX actions, I want to push some new stuff to my array.

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

So, 50% of the time, the new element is added to the view. But the other 50%, nothing happens. And it's like super frustrating; bc if I wrap that within $scope.$apply(), I got a "$digest already in progress" error. Wrapping that into $timeout doesn't help either.

And when I inspect my element scope using the Chrome extension; I can see the new data is there and the $scope.items value is correct. But the view is just not taking care of adding that to the DOM.

Thanks!

I'm having serious troubles understanding AngularJS sometimes. So I have a basic array in my controller like

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

I'm ngRepeating in my template over the items array ng-repeat="item in items". Super straightfoward so far. After a couple of UX actions, I want to push some new stuff to my array.

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

So, 50% of the time, the new element is added to the view. But the other 50%, nothing happens. And it's like super frustrating; bc if I wrap that within $scope.$apply(), I got a "$digest already in progress" error. Wrapping that into $timeout doesn't help either.

And when I inspect my element scope using the Chrome extension; I can see the new data is there and the $scope.items value is correct. But the view is just not taking care of adding that to the DOM.

Thanks!

Share Improve this question asked Mar 22, 2013 at 12:39 spacenickspacenick 1,1853 gold badges14 silver badges19 bronze badges 3
  • can you create a demo at jsfiddle.net – Arun P Johny Commented Mar 22, 2013 at 12:42
  • 2 Its surely related to the digest cycle. We need you to post the code you use to update the array. – Caio Cunha Commented Mar 22, 2013 at 12:48
  • 2 I'm getting this problem as well, would love an answer! – Samuel Commented May 22, 2013 at 6:11
Add a comment  | 

3 Answers 3

Reset to default 21

You are modifying the scope outside of angular's $digest cycle 50% of the time.

If there is a callback which is not from angularjs; (posibbly jquery). You need to call $apply to force a $digest cycle. But you cannot call $apply while in $digest cycle because every change you made will be reflected automatically already.

You need to know when the callback is not from angular and should call $apply only then.

If you don't know and not able to learn, here is a neat trick:

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

As pointed out by Umur Kontacı, you are making model changes outside of the digest cycle sometimes. However, instead of working around this problem and trying to detect whether you are in an apply/digest context or not, I suggest you make sure this never happens.

The main cause for this problem is that your function is called as a reaction to a DOM event. E.g.

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

This is where your $apply() needs to go, not within the function. Otherwise your whole code will be littered with such distinctions sooner or later. Assuming there is a scope in the context of this event handler, you can write:

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

However, there is one caveat you have to be aware of: When you trigger a click event from your code, you will run into the problem that a digest cycle is already in progress. This is where you need the $timeout. The answers to this question cover this problem very well.

I had the same issue, and my fix was to watch which controllers are being called in nested directives.

# 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>

The bug here is the nested directive creates a second controller in prototype chain (a duplicate of storeController), which the parent template doesn't have access to. To resolve write the nested controller like so:

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

There are better ways to create the inheritance chain, but this will resolve the issue for many people learning AngularJS.

发布评论

评论列表(0)

  1. 暂无评论