I'm trying to make a multi-filter for ng-repeat. But when my filter returns an empty array, it pops up:

Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: task in tasks | multipleFilter:filter, Duplicate key: undefined:undefined, Duplicate value: undefined 

HTML:

 <div ng-repeat="task in tasks | multipleFilter:filter"> 

Filter:

 function multipleFilter() { return function(input, filters) { console.log(arguments); for (var index in input) { var current = input[index]; for (var filter in filters) { console.log("filter is", filter, filters[filter]); if (filters[filter] == "all") continue; if (Array.isArray(filters[filter]) && filters[filter].indexOf(current[filter]) === -1) delete input[index]; } } console.log("Outer input: ", input); return input; } } 

An example on JSFiddle (sorry for the mess in HTML). You need to make the filters work.

  • remove all unnecessary from the example, and add to the question an example of the input data for the filter and an example of the output. - Grundy
  • @Grundy, there is nothing superfluous except HTML, and even more JS is more important here than HTML. - blits
  • in the example, there is too much markup and code now, plus it is not clear what exactly and by what principle is being filtered. - Grundy
  • @Grundy, made the code cleaner, look jsfiddle.net/tspb6exc/1 - blits
  • What happens in the select function? some kind of strange magic with the transformation of a string into an array. And I still do not see the description: how exactly the filter should work - Grundy

1 answer 1

The main problem is the wrong filter.

delete input[index] deletes the element, but does not change the length property of the array and does not shift the remaining indices. The result is an array of the form

 [a,b,undefined,undefined] 

and since there are two identical objects undefined , ng-repeat drops.

A quick workaround can be to use track by $index - in this case, the uniqueness will be determined by the element number, but even empty elements will be displayed.

The correct thing is to fix the filter itself.

Now when using delete or splice , the source collection changes. To fix it, you can use the Array.prototype.filter function, which returns a new array without changing the original one.

  • If I use track by , the filter is not updated at all. How to remove an item from the filter? - blits
  • Hmm, well, I used Array.prototype.splice , the exception was gone, but I get an empty array on the input and output. - blits
  • @blits, in this case, obviously the problem is in the filter - Grundy
  • More specifically? I don’t know what the problem may be. - blits 3:51 pm
  • I understood what the problem was. The value that I give in the filter is written to $scope.tasks . But how to make it not recorded there? - blits 3:53 pm