0

I'm using ng-repeat on an array of objects similar to this:

var objects = [
  {
    name: 'test',
    id: 1234,
    category: 'a'
  },
  {
    name: 'sample',
    id: 4567,
    category: 'b'
  },
  {
    name: 'example',
    id: 7890,
    category: 'a'
  }, ...
];

<p ng-repeat="object in objects">{{object.name}}<p>

This array contains over a dozen objects with 4 distinct categories. What I want to do is split these objects up in my UI to display each under its category heading:

Category: a test example Category: b sample

Is there any way to accomplish this with one ng-repeat? My current thinking is that I'll need to split this up in to four identical ng-repeats based on data that I 'categorize' separately in my controller. Just hoping there was a DRYer way to accomplish this.

MattDionis
  • 3,534
  • 10
  • 51
  • 105

1 Answers1

2

Working PLUNKER

To solve this problem, I'm using two Angular 'filters', OrderBy, which receives a property of an object an sorts that object based on that. The second is the 'Filter filter', which receives an array, do some operation and send it back. I'm using your object as $scope.things.

Markup:

  <body ng-app="app" ng-controller="ctrl">
    <div ng-repeat="thing in things | orderBy: 'category' | thingsFilter">
      <p>{{thing}} </p>
    </div>

    <h1>Hello Plunker!</h1>
  </body>

First, I'm using the orderBy, which will order by array based on the things.category property. Then, with the ordered array, I'm applying an Angular custom filter.

app.js

app.filter('thingsFilter', function () {
  return function (things) {
    var filtered = []; //Return array.
    for (var i=0; i< things.length; i++ ){ //Iterate over things.
      if (i > 0 ) { //To make sure I won't compare with things[-1]
        if ((things[i].category) != (things[i-1].category)) {
          //If category of last item is different, add the name of category.
          filtered.push("_____CATEGORY: " + things[i].category + ":");
        }
      } else { //Insert the first category.
        filtered.push("_____CATEGORY: " + things[i].category + ":");
      };
      console.log(things[i]); //Just to see what is happening.
      filtered.push(things[i].name); //Inserting the name of the thing.
    };
    console.log(filtered); //The final array to
    return filtered;       //be returned here.
  };
});

The input of the filter is the things object, which has been ordered by the orderBy. So, I have an ORDERED array. Now, I had created the filtered variable, which will hold all the value to be sent back.

Next, I'm lookin to see if the variable i is greater than zero, so I won't compare with a negative index and bug my code. If the index is zero, then I will add a category line.

Since the array is ordered, I can check if the category of the last array is different than the actual one. If it is, then I will add the category in the array with filtered.push("____CATEGORY...").

At the end of each for loop, I will push the things[i].name to the array to be returned. And, at the end, I will return the filtered array, so my ng-repeat can use it.

Working PLUNKER

Rodmentou
  • 1,610
  • 3
  • 21
  • 39