angular grouping filter

后端 未结 3 1164
独厮守ぢ
独厮守ぢ 2021-01-02 01:35

Following angular.js conditional markup in ng-repeat, I tried to author a custom filter that does grouping. I hit problems regarding object identity and the model being watc

相关标签:
3条回答
  • 2021-01-02 01:47

    It looks like the real problem here is you're altering your input, rather than creating a new variable and outputing that from your filter. This will trigger watches on anything that is watching the variable you've input.

    There's really no reason to add a "grouped == true" check in there, because you should have total control over your own filters. But if that's a must for your application, then you'd want to add "grouped == true" to the result of your filter, not the input.

    The way filters work is they alter the input and return something different, then the next filter deals with the previous filters result... so your "filtered" check would be mostly irrelavant item in items | filter1 | filter2 | filter3 where filter1 filters items, filter2 filters the result of filter1, and filter3 filters the result of filter 2... if that makes sense.

    Here is something I just whipped up. I'm not sure (yet) if it works, but it gives you the basic idea. You'd take an array on one side, and you spit out an array of arrays on the other.

    app.filter('group', function(){
       return function(items, groupSize) {
          var groups = [],
             inner;
          for(var i = 0; i < items.length; i++) {
             if(i % groupSize === 0) {
                inner = [];
                groups.push(inner);
             }
             inner.push(items[i]);
          }
          return groups;
       };
    });
    

    HTML

    <ul ng-repeat="grouping in items | group:3">
        <li ng-repeat="item in grouping">{{item}}</li>
    </ul>
    

    EDIT

    Perhaps it's nicer to see all of those filters in your code, but it looks like it's causing issues because it constantly needs to be re-evaluated on $digest. So I propose you do something like this:

    app.controller('MyCtrl', function($scope, $filter) {
       $scope.blueprints = [ /* your data */ ];
       $scope.currentPage = 0;
       $scope.pageSize = 30;
       $scope.groupSize = 3;
       $scope.sortPty = 'stuff';
    
       //load our filters
       var orderBy = $filter('orderBy'),
           startFrom = $filter('startFrom'),
           limitTo = $filter('limitTo'),
           group = $filter('group'); //from the filter above
    
       //a method to apply the filters.
       function updateBlueprintDisplay(blueprints) {
            var result = orderBy(blueprints, $scope.sortPty);
            result = startForm(result, $scope.currentPage * $scope.pageSize);
            result = limitTo(result, $scope.pageSize);
            result = group(result, 3);
            $scope.blueprintDisplay = result;
       }
    
       //apply them to the initial value.
       updateBlueprintDisplay();
    
       //watch for changes.
       $scope.$watch('blueprints', updateBlueprintDisplay);
    });
    

    then in your markup:

    <ul ng-repeat="grouping in blueprintDisplay">
       <li ng-repeat="item in grouping">{{item}}</li>
    </ul>
    

    ... I'm sure there are typos in there, but that's the basic idea.


    EDIT AGAIN: I know you've already accepted this answer, but there is one more way to do this I learned recently that you might like better:

    <div ng-repeat="item in groupedItems = (items | group:3 | filter1 | filter2)">
        <div ng-repeat="subitem in items.subitems">
        {{subitem}}
        </div>
    </div>
    

    This will create a new property on your $scope called $scope.groupedItems on the fly, which should effectively cache your filtered and grouped results.

    Give it a whirl and let me know if it works out for you. If not, I guess the other answer might be better.

    0 讨论(0)
  • 2021-01-02 01:48

    Regardless, I'm still seeing the $digest error, which is puzzling: plnkr.co/edit/tHm8uYfjn8EJk3cG31DP – blesh Jan 22 at 17:21

    Here is the plunker forked with the fix to the $digest error, using underscore's memoize function: http://underscorejs.org/#memoize.

    The issue was that Angular tries to process the filtered collection as a different collection during each iteration. To make sure the return of the filter always returns the same objects, use memoize.

    http://en.wikipedia.org/wiki/Memoization

    Another example of grouping with underscore: Angular filter works but causes "10 $digest iterations reached"

    0 讨论(0)
  • 2021-01-02 01:57

    You can use groupBy filter of angular.filter module, and do something like this:
    usage: (key, value) in collection | groupBy: 'property'or 'propperty.nested'
    JS:

    $scope.players = [
      {name: 'Gene', team: 'alpha'},
      {name: 'George', team: 'beta'},
      {name: 'Steve', team: 'gamma'},
      {name: 'Paula', team: 'beta'},
      {name: 'Scruath', team: 'gamma'}
    ];
    

    HTML:

    <ul ng-repeat="(key, value) in players | groupBy: 'team'" >
      Group name: {{ key }}
      <li ng-repeat="player in value">
        player: {{ player.name }} 
      </li>
    </ul>
    <!-- result:
      Group name: alpha
        * player: Gene
      Group name: beta
        * player: George
        * player: Paula
      Group name: gamma
        * player: Steve
        * player: Scruath
    
    0 讨论(0)
提交回复
热议问题