20

controller

    @RequestMapping(value = "/graphs", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public Collection<Graph> getSkeletonGraph()
    {
        log.debug("REST request to get current graphs");
        return graphService.getSkeletonGraphs();
    }

Angular call

    $scope.graphs = [];
    Graph.getGraphs().$promise.then(function(result)
    {
        $scope.graphs = result;
    });



    angular.module('sampleApplicationApp').factory('Graph', function($resource)
     {
      return {
        getGraphs: function() {
           return    $resource('api/graphs/:id').query();
      }
     };
    })

I am not sure why using the filter i get the exception.

looked also in angular doc https://docs.angularjs.org/error/filter/notarray My result is array but not sure why I am getting such exception.

Sample result from backend i am getting.

[{"id":"135520b0-9e4b-11e5-a67e-5668957d0149","area":"Bingo","models":[],"enumerateds":[]},{"id":"0db925e0-9e53-11e5-a67e-5668957d0149","area":"jin","models":[],"enumerateds":[]},{"id":"7a717330-9788-11e5-b259-5668957d0149","area":"Product","models":[],"enumerateds":[]},{"id":"402d4c30-980f-11e5-a2a3-5668957d0149","area":"fgfgfg","models":[],"enumerateds":[]},{"id":"404b77b0-9e53-11e5-a67e-5668957d0149","area":"olah","models":[],"enumerateds":[]},{"id":"cd071b10-9e52-11e5-a67e-5668957d0149","area":"lolo","models":[],"enumerateds":[]},{"id":"d9808e60-9710-11e5-b112-5668957d0149","area":"catalog","models":[],"enumerateds":[]},{"id":"2aaca9f0-97e2-11e5-91cd-5668957d0149","area":"btg","models":[],"enumerateds":[]},{"id":"955e9ed0-978c-11e5-93fd-5668957d0149","area":"promotions","models":[],"enumerateds":[]},{"id":"1e441d60-980f-11e5-a2a3-5668957d0149","area":"hjuhh","models":[],"enumerateds":[]},{"id":"fb96dfe0-978d-11e5-93fd-5668957d0149","area":"voucher","models":[],"enumerateds":[]}]

html

<li ng-repeat="g in graphs track by $index | filter:searchText"></li>
0

2 Answers 2

75

The problem is occurring because you are using track by $index before you are applying your filter. To resolve this, change your expression to:

<li ng-repeat="g in graphs | filter:searchText track by $index"></li>

The track by expression should always be at the last, after all your filters. Its a rule mentioned in the docs: ngRepeat

Explanation:

When you don't use track by $index in ngRepeat, the input for all the filters used is the array, that is, if its

ng-repeat="item in items | filter1 | filter2", 

then items is the input passed to the filters by default and the filtering is done on this input.

However, when you use track by $index, the input to the filters becomes $index instead of items and therefore the error:

Expected array(read: items) but received 0(read: $index).

Therefore, to counter this, the array is first passed through all the filters and the filtered result is used with track by $index.

Hope this clears it up.

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

6 Comments

could you please describe the logic behind your suggestion
Its a rule mentioned in the docs. Filters should be applied before the track by expression. See in docs: docs.angularjs.org/api/ng/directive/ngRepeat
After spending 2 hours trying to figure out why the filter on the Angular website was working and mine wasn't this was the only answer which solved my problem! Needless to say I would probably need to open and read again the docs. However that's very anti-intuitive and the error doesn't help at all, why track by $index should be always the last expression? Makes no sense in my head.
There is a reason for that. When you don't use track by $index, the input for all the filters is the array, that is, if its item in items, items is the input passed to the filters. However, when you use track by $index, the input to the filters becomes $index instead of items and therefore the error: Expected array(items) but received 0($index). Hope this clears it up.
brilliant, spent more than an hour
|
3

You should always use track by at the end of expression

<li ng-repeat="g in graphs | filter:searchText track by $index"></li>

Since while evaluating an expression for ng-repeat angular needs the final result for track by to work. If you provide it at the end, your filter will be applied and track by is computed on final output. You can see the source code at angular docs.

According to the documentation of ng-repeat

If you are working with objects that have an identifier property, you should track by the identifier instead of the whole object. Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this signifincantly improves rendering performance. If you don't have a unique identifier, track by $index can also provide a performance boost.

Comments

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.