3

i am about to bang my head to walls. i thought i had an understanding of how angular works (filters too). but i just cant find the problem about my filter. it causes infdig. and i even dont change source array in filter.

(function () {

angular.module('project.filters').filter('splitListFilter', function () {
    return function (data, chunk) {
        if(!data || data.length === 0){
            return data;
        }

        var resultArray = [];
        for (var i = 0, j = data.length; i < j; i += chunk) {
            resultArray.push(data.slice(i, i + chunk));
        }

        return resultArray;
    };
});

})();

i have lists where i need to split data to x columns. it is complicated to solve with limitTo.

(limitTo: $index*x | limitTo: $last ? -z : -x)

it causes a dirty template file. so i decided to create a filter which splits an array to groups.

[1,2,3,4,5,6,7,8] -> [[1,2,3],[4,5,6],[7,8]]

so i can easily use it in my template.

Can u help me about what causes infdig in this filter?

Edit: the error message itself looks strange with some numbers in that don't appear anywhere in the code, which can be seen at http://plnkr.co/edit/pV1gkp0o5KeimwPlEMlF

10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":23,"oldVal":20}],[{"msg":"fn: regularInterceptedExpression","newVal":26,"oldVal":23}],[{"msg":"fn: regularInterceptedExpression","newVal":29,"oldVal":26}],[{"msg":"fn: regularInterceptedExpression","newVal":32,"oldVal":29}],[{"msg":"fn: regularInterceptedExpression","newVal":35,"oldVal":32}]]

HTML Template

<div class="row" ng-repeat="chunk in docProfile.SysMedicalInterests | splitListFilter: 3">
    <div class="col-md-4" ng-repeat="medInterest in chunk">
        <label style="font-weight:normal;">
        <input type="checkbox" value="{{medInterest.ID}}" ng-click="docProfile.saveInterest(medInterest.ID)" ng-checked="docProfile.isMedChecked(medInterest.ID)"> {{medInterest.Name}}
        </label>
     </div>
</div>

Controller Code

var me = this;
me['SysMedicalInterests'] = null;

    var loadMedicalInterests = function(){
        var postData = { 'Data': me['data']['subData'] };
        return docService.loadMedicalInterests(postData).then(function(resp)      {
            me['SysMedicalInterests'] = resp['data'];
        }, function(){});
    };

loadMedicalInterests();

so array starts with a null reference and loads data from server. which changes array causes a second filter run. but it doesnt stop after that

Edit: here is plunkr http://plnkr.co/edit/OmHQ62VgiCXeVzKa5qjz?p=preview

Edit: related answer on so https://stackoverflow.com/a/21653981/1666060 but this still doesn't explain angular built in filters.

here is angularjs limitTo filter source code

https://github.com/angular/angular.js/blob/master/src/ng/filter/limitTo.js#L3

6
  • 1
    I've added the error message I get when I run your filter. If you're not getting anything like that, feel free to edit/remove. Commented Mar 18, 2015 at 8:50
  • are you using $watch somewhere? Commented Mar 18, 2015 at 8:51
  • How are you using the filter ? Show the html. Commented Mar 18, 2015 at 8:53
  • What Angular version are you using? Commented Mar 18, 2015 at 8:56
  • i am using AngularJS v1.3.4. and i am not using watch anywhere in code. i ll post my template and controller code by editing question Commented Mar 18, 2015 at 9:54

2 Answers 2

3

About what exactly causes it, I suspect is something to do with the fact that every time you run the filter a new array reference is created and returned. However, Angular's built-in filter filter does the same thing, so I'm not sure what is going wrong. It could be something to do with the fact that it's an array of arrays that is being returned.

The best I have come up with is a workaround/hack, to cache the array reference manually as an added property, which I've called $$splitListFilter on the array, and only change it if it fails a test on angular.equals with the correct results calculated in the filter:

app.filter('splitListFilter', function () {
    return function (data, chunk) {
        if(!data || data.length === 0){
            return data;
        }

        var results = [];
        for (var i = 0, j = data.length; i < j; i += chunk) {
          results.push(data.slice(i, i + chunk));
        }

        if (!data.$$splitListFilter || !angular.equals(data.$$splitListFilter, results)) {
          data.$$splitListFilter = results;
        }
        return data.$$splitListFilter;
    };
});

You can see this working at http://plnkr.co/edit/vvVJcyDxsp8uoFOinX3V

The answer uses Angular 1.3.15

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

1 Comment

thanks, i guess this should do it. but i cant understand. i inspected source code of limitTo filter. how does it work than?
0

The JS fiddle works fine: http://jsfiddle.net/3tzapfhh/1/

Maybe you use the filter wrongly.

<body ng-app='app'>
  <div ng-controller='ctrl'>
    {{arr | splitListFilter:3}}
  </div>  
</body>

1 Comment

this fiddle uses angularjs version 1.2.1. maybe this is what differs. i am trying to run same thing with angular js v1.3.4

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.