0

I am using bootstrap to display a grid of projects with each row having 3 columns. In order to accomplish this, I am using ng-repeat twice like below.

<div class="row" ng-repeat="chunk in projects">
  <div class="col-sm-4" ng-repeat="project in chunk | orderBy:'title'">
    {{project.title}}
  </div>
</div>    

I want to be able to sort the project based on its title field. Applying a filter only sorts a subset of the whole list i.e. sorts at the chunk level rather than the projects level.

var projects = [[{"title":"Z"},{"title":"A"},{"title":"M"}],
  [{"title":"Z"},{"title":"A"},{"title":"M"}]];

After the orderBy happens, the rows are A M Z, A M Z. How do I get it to display A A M, M Z Z?

Here is the plunk for the above problem. //EDIT : The above plunk points to the solution because I updated the plunk.

3
  • 2
    Why would you expect that ordering on the inner ng-repeat would affect the outer? Either order on the outer or consider flattening your data structure into something that more closely resembles your output. Commented Mar 25, 2016 at 19:21
  • Yeah, you'll need to flatten the structure out more. Commented Mar 25, 2016 at 19:22
  • From what I understood, you are suggesting that I modify projects as var = [{"title":"A"},{"title:"B"},{"title":"C"},{"title":"A"},{"title:"B"},{"title":"C"}]. This creates a problem another problem. I want the outer div with class row to conatin exactly three inner divs with class col-sm-4. It cannot be achieved with the suggested data structure. Commented Mar 25, 2016 at 19:34

3 Answers 3

1

You'll need a custom filter that will turn your sub-arrays into a single array. The whole point of having separate arrays would be to isolate the contents, which is the opposite of what you want.

Filter:

yourAppModule
.filter('titleSort', function(){
    return function(input){
        var fullArray = []; //Will be the output array    
        for(var i=0;i<input.length;i++)            
            fullArray.concat(input[i]);
            //Iterates through all the arrays in input (projects)
            //and merges them into one array            
        fullArray = fullArray.sort(function(a,b){return a.title>b.title});
            //Sorts it by the title property
        var chunks = [];
        var currentChunk;
        for(var i=0;i<fullArray.length;i++){
            if(i%3===0){
                currentChunk = [];
                chunks.push(currentChunk);
            }
            currentChunk.push(fullArray[i]);   
        }
        return chunks;
    };
} ...

Now your view can be this:

<div class="col-sm-4" ng-repeat="project in projects | titleSort">
    {{project.title}}
</div>
Sign up to request clarification or add additional context in comments.

4 Comments

I want the div with class row to contain exactly 3 divs with class col-sm-4. So if there are more than 3 projects in projects variable, I want the extra projects to go inside a new div with class row.
@PravinUmamaheswaran I edited it to re-split the full array after sorting it.
I tried your edited solution. I get a $rootScope.infdig error. Turns out, the model for ng-repeat keeps on getting changed each time the filter gets called which results in $digest getting called an infinite number of times. I'm trying to solve this issue using $scope.$watch. Will update if I work out a solution.
Ok, well that sounds like a problem external to the filter. What I gave is ultimately some pretty simply rearrangement in an isolated scope.
1

I was able to solve this problem finally through filter chaining. I used angular-filter module/library but this can be even done without angular-filter.

<div class="container" ng-controller="ExampleController as exampleVm">
<div class="row" ng-repeat="chunk in exampleVm.projects|  chunkBy: 'title' | groupBy : 3">
  <div class="col-sm-4" ng-repeat="project in chunk">
    {{project.title}}
  </div>
</div>

I flattened the array and made it look like this.

var projects = [{"title:Z"},{"title":"A"},{"title":"M"},{"title:Z"},{"title":"A"},{"title":"M"}]

In the filter chain, I order the elements in the flattened array first by title and then divide it into subarrays of 3 elements each. Hope this helps.

You can find the plunk here.

Comments

0

try this. may be help you.

var app = angular.module("app",[])
app.controller('ctrl',['$scope', function($scope){
        $scope.data = [[{"title":"Z"},{"title":"A"},{"title":"M"}],
  [{"title":"Z"},{"title":"A"},{"title":"M"}]];
  
  $scope.data2 = [];
  angular.forEach( $scope.data,function(d){
    angular.forEach(d,function(d1){
      $scope.data2.push(d1);
      })
    })
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<div ng-app="app" ng-controller="ctrl">
<div class="item item-checkbox">
   <div class="row">
  <div class="col-sm-4" ng-repeat="project in data2 | orderBy:'title'">
    {{project.title}}
  </div>
</div>    
</div>

1 Comment

I am quite new to angular js and I did not quite understand the angular.forEach() block of code. I tried to use this code as it is but the grid columns won't print. I don't know if I am messing something up or not.

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.