AngularJS Group-By Filter

Filter to define when a field in an array of data changes from the previous value. Allows multiple filters and can be used in conjunction with OrderBy. A future change will be to allow an array of fields to group by to be passed so that the multiple group-by filters don't have to re-iterate through the array for each one.

HTML

<div ng-app="myApp">
		<div ng-controller='TestGroupingCtlr'>
			<div ng-repeat="item in MyList | filter: {status: 'Closed'} | groupBy:'groupfield' " >
				<h2 ng-show="item.groupfield_CHANGED">{{item.groupfield}}</h2>
				<ul>
					<li>{{item.whatever}} - Status: {{item.status}}</li>
				</ul>
			</div>

		</div>

</div>

JavaScript

var app=angular.module('myApp',[]);

    app.controller('TestGroupingCtlr',function($scope) {

			$scope.MyList = [
				{groupfield: 'Day Before', whatever: 'Server X down', status: 'Open'},
				{groupfield: 'Yesterday', whatever: 'Access issues', status: 'Open'},
				{groupfield: 'Yesterday', whatever: 'Server Z is down', status: 'Closed'},
				{groupfield: 'Today', whatever: 'Network problem', status: 'Closed'},
				{groupfield: 'Today', whatever: 'Network is down', status: 'Closed'}
			];


		})


    /*
	 * groupBy
	 *
	 * Define when a group break occurs in a list of items
	 *
	 * @param {array}  the list of items
	 * @param {String} then name of the field in the item from the list to group by
	 * @returns {array}	the list of items with an added field name named with "_new"
	 *					appended to the group by field name
	 *
	 * @example		<div ng-repeat="item in MyList  | groupBy:'groupfield'" >
	 *				<h2 ng-if="item.groupfield_CHANGED">{{item.groupfield}}</h2>
	 *
	 *				Typically you'll want to include Angular's orderBy filter first
	 */
        
    app.filter('groupBy', function(){
		return function(list, group_by) {

		var filtered = [];
		var prev_item = null;
		var group_changed = false;
		// this is a new field which is added to each item where we append "_CHANGED"
		// to indicate a field change in the list
		var new_field = group_by + '_CHANGED';

		// loop through each item in the list
		angular.forEach(list, function(item) {

			group_changed = false;

			// if not the first item
			if (prev_item !== null) {

				// check if the group by field changed
				if (prev_item[group_by] !== item[group_by]) {
					group_changed = true;
				}

			// otherwise we have the first item in the list which is new
			} else {
				group_changed = true;
			}

			// if the group changed, then add a new field to the item
			// to indicate this
			if (group_changed) {
				item[new_field] = true;
			} else {
				item[new_field] =...