0
votes

I would like to create table with filters in table header. Filter is list of unique values in each column. Here is simplified code:

<table>
  <tr>
       <th class="dropdown" ng-repeat="field in data.columns">
         <span>{{field.title}}</span>
         <ul class="dropdown-menu">
           <li ng-repeat="item in unique(data.items, field)"><checkbox> {{item.text}}</li>
         </ul>
       </th> 
  </tr>
  <tr ng-repeat="item in data.items"></tr>
</table>

I use same object array for filter and table but filter create copy of array and remove from copy values that are repeated. And here is my problem.

When I copy array as array.slice(0) deleted values not in filter but in table too (array contains objects). My problem is in references, so I used deepcopy as jQuery.extend(true, [], array) and angular throws error:

[$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations

My data look like this:

[{id: 1, title: 'AAA', something: [{id: 1, text: "A"}]}, {id: 2, title: 'AAAA', something: [{id: 2, text: "AA"}]}]

Problem is in property something (array.slice(0) donť copy and $.extend copy but angular get error)

Thanks for advices

2
angular.copy() the angular way. - Jai
I think your problem will disappear if you move some of the logic of manipulating the arrays to your controller. Try moving the call to unique(data.items, field) to a controller function. If you can reduce one of the ng-repeat, that will significantly reduce the number of digest cycles. - Matt
Another angular approach could be the use of $filter('filter') or creating a custom filter for the ng-repeat. - Matt

2 Answers

1
votes

You haven't posted the code for the filter so I must assume what's happening. I think you're not checking if all elements of list are unique before making a copy. This causes the filter to change the data every digest, triggering infinite number of digests - hence the error. Your list is never stable.

To solve this at the beginning of the filter add check for uniqueness of elements and if they are already unique (for example after first pass of filter) just return input object. This way model will stabilize.

0
votes

Here is my code for get unique value from objects array:

    function toUnique(a, property, innerProperty) {
        var lastIndex = a.length;
        if (lastIndex === 0 || lastIndex === undefined)
            return a;
        var copyarr = jQuery.extend(true, [], a);
        if (property !== undefined) {
            while (prevIndex = --lastIndex) {
                while (prevIndex--) {
                    var obj1 = copyarr[lastIndex];
                    var obj2 = copyarr[prevIndex];

                    if (obj1 !== undefined) {
                        if (copyarr[lastIndex][property] instanceof Array && copyarr[prevIndex][property] instanceof Array)
                            unique(copyarr[lastIndex][property], copyarr[prevIndex][property], innerProperty);
                        else
                            obj1[property] !== obj2[property] || copyarr.splice(prevIndex, 1);
                    }
                }
            }
            return copyarr;
        } else {
            while (prevIndex = --lastIndex)
                while (prevIndex--)
                    copyarr[lastIndex] !== copyarr[prevIndex] || copyarr.splice(prevIndex, 1);
            return copyarr;
        }
    }

function unique(array1, array2, innerProperty) {
    for (var i = 0; i < array1.length; i++) {
        removeDuplicates(array1, i + 1, array1[i], innerProperty);
        removeDuplicates(array2, 0, array1[i], innerProperty);
    }
    for (var i = 0; i < array2.length; i++) {
        removeDuplicates(array2, i + 1, array2[i], innerProperty);
    }
}

function removeDuplicates(arr, startPos, p, property) {
    for (var i = startPos; i < arr.length;) {
        if (p[property] == arr[i][property]) {
            arr.splice(i, 1);
        } else {
            i++;
        }
    }
}

Using:

    var a = [{id: 1, title: "AAAA"}, {id: 2, title: "BBBB"}, {id: 1, title: "AAAA"}]
    unique(a, "title", null); //return {id: 1, title: "AAAA"}, {id: 2, title: "BBBB"}

    var b = [{id: 1, title: "AAAA", authors: [{id: 15, name: "John"}, {id: 25, name: "Peter"}, {id: 16, name: "John"}]},
{id: 1, title: "BBBB", authors: [{id: 15, name: "John"}, {id: 25, name: "Peter}]}]

    unique(b, "authors", "name")  //return: [{id: 1, title: "AAAA", authors: [{id: 15, name: "John"}, {id: 25, name: "Peter}]},
{id: 1, title: "BBBB", authors: []}]