Earlier today a colleague asked me how one would go about grouping data within an ng-repeat. I had never actually had to do this before, which made it an interesting problem to solve.
What does it mean to group data? Essentially, we’re picking an arbitrary common, unique value among a set of objects and putting them in groups. This unique value would be a key identifier for the group. I Googled a bit and saw a few Angular filters that would perform grouping, but they were a little too ham-fisted for my taste or were too tightly coupled with a library or framework.
This made me think that the built-in filtering mechanism should be able to handle this if only I could determine the unique values. Determine unique values, as it turns out, is quite easy to do. Creating a custom filter to out unique keys looks like this:
var uniqueFilter = function () { return function (collection, propName) { var result = [], keys = []; angular.forEach(collection, function (item) { var key = item[propName]; if (keys.indexOf(key) === -1) { keys.push(key); result.push(item); } }); return result; }; };
Once we have a set of unique keys, we can then filter based on the key value to get all items that are in the group. This mechanism is effectively performing a second filter to get the group’s item. The HTML is straight forward:
<div ng-repeat="grp in vm.items| unique:'groupName' | orderBy:'groupName'"> Group name: {{ grp.groupName }} <p ng-repeat="item in vm.cashOnHands | filter:{groupName:grp.groupName}"> {{ item.name }} </p> </div>
For the final product, I made it a little nicer with collapsible accordions and a table within the body of the accordion to show the items within the group more clearly.
One thought on “Grouping data with Angular”