I have an 'Add Item' button on the screen which adds a new item to a list when it's clicked.
I use $scope.$watchCollection
to watch a function which returns a list of all visible items.
When I clicked the 'add item' button, I received unlimited digest loop error. It seems that $watchCollection clones the list, and then the newCollection is alwasy not equle the oldCollection.
JS Bin Demo: https://jsbin.com/mavolecipu/1/edit?html,js,output
function MainController($scope) {
var ctrl = this;
var _index = 1;
var _visibleItems = [];
var _allItems = [];
ctrl.addItem = addItem;
ctrl.visibleItems = [];
$scope.$watchCollection(getVisibleItem, function (newVal, oldVal) {
// it looks like the newVal is always not equal oldVal??
if(newVal!== oldVal){
ctrl.visibleItems = newVal;
}
});
function addItem() {
_allItems.push({
index: _index,
isVisible: true
});
_index = _index+1;
}
function getVisibleItem() {
var newVisibleItems = _(_allItems).filter({isVisible: true}).value();
// use same reference
_visibleItems.length = 0;
_.merge(_visibleItems, newVisibleItems);
return _visibleItems;
}
}
Your issue is that every time a digest cycle runs, getVisibleItem
is called. That function clears _visibleItems
and then adds everything back to it via _.merge
. Because _.merge
makes deep copies of the items (thus causing them to be different references), it triggers $watchCollection
, which will include another digest cycle being fired, causing an infinite loop of digest cycles.
Rather than clearing _visibleItems
and then adding items back into it, I recommend you do the work of actually adding/removing items that have had their visibility changed (i.e. remove items in _visibleItems
that have isVisible=false
and add in items that are only in _allItems
with isVisible=true
.
Alternately, replacing _.merge(_visibleItems, newVisibleItems)
with a simple for-loop or [].push.apply(_visibleItems, newVisibleItems
will resolve your issue.