1

Just ran into an infinite $digest loop when passing parameters to a filter defined on the $scope.

In HTML:

<ul id="albumListUL" class="fa-ul">
    <li ng-repeat="album in GoogleList | myFilter:Field:Reverse track by album.id.$t">
        <i class="fa-li fa fa-google-plus"></i>
        <a href="#" id="{{album.gphoto$id.$t}}" class="g_album" alt="{{album.title.$t}}">
        {{album.title.$t}} <span class="badge">{{album.gphoto$numphotos.$t}}</span>
        </a>
    </li>
</ul>

Controller:

.controller("AlbumListController", ['$scope', 'AlbumListService', function($scope, AlbumListService) {
    $scope.Field = "published";
    $scope.Reverse = true;

    $scope.GoogleList = AlbumListService.GoogleList; 
}])

Filter:

.filter('myFilter', function() {
    return function(items, field, reverse) {
        items.sort(function(a, b){
            var aValue = a[field].$t.toLowerCase();
            var bValue = b[field].$t.toLowerCase();

            if(reverse)
            {
                return ((aValue > bValue) ? -1 : ((aValue < bValue) ? 1 : 0));
            } else {
                return ((aValue < bValue) ? -1 : ((aValue > bValue) ? 1 : 0));
            }
        });

        return items;
    };
})

If I run the code like this I will get the $digest loop error but the output will be sorted. If I instead of using $scope.Field and $scope.Reverse writes myFilter:'published':true it will work without the error. I have checked everything else, disabled all directives and other stuff that might interfere still the same issue.

Anyone have some good input on this?

2
  • Can you please show what is in AlbumListService.GoogleList? Commented Feb 2, 2016 at 6:51
  • 2
    As of my understanding every filter returns new instance of objects which angular thinks of like a change and kicks of new digest cycle therefore. Commented Feb 2, 2016 at 7:13

1 Answer 1

2

After some tinkering I have figured this one out. The issue is that the array is passed, as all arrays in javascript, by reference. So when ever the filter fires the function passed to the array.sort() it will trigger the watcher of the array.

So by making a shallow copy of the array, sort it and then returning it we can get around this issue. I also added caching with underscoreJS memoize to speed it up.

Created a Plunker with the three examples: https://embed.plnkr.co/ul9ZiK/

Did a quick blog post of the issue: http://www.hackviking.com/development/angularjs-digest-loop-when-filtering-array-of-objects/

Sign up to request clarification or add additional context in comments.

1 Comment

I've been searching for this answer for hours. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.