I'm new to Angular and would like to learn the best way to handle a problem. My goal is to have a reusable means to create group by headers. I created a solution which works, but I think this should be a directive instead of a scope function within my controller, but I'm not sure how to accomplish this, or if a directive is even the right way to go. Any inputs would be greatly appreciated.
See my current approach working on jsFiddle
In the HTML it's a simple list using ng-repeat where I call my newGrouping() function on ng-show. The function passes a reference to the full list, the field I want to group by, and the current index.
<div ng-app>
<div ng-controller='TestGroupingCtlr'>
<div ng-repeat='item in MyList'>
<div ng-show="newGrouping($parent.MyList, 'GroupByFieldName', $index);">
<h2>{{item.GroupByFieldName}}</h2>
</div>
{{item.whatever}}
</div>
</div>
</div>
In my controller I have my newGrouping() function which simply compares the current to the previous, except on the first item, and returns true or false depending upon a match.
function TestGroupingCtlr($scope) {
$scope.MyList = [
{GroupByFieldName:'Group 1', whatever:'abc'},
{GroupByFieldName:'Group 1', whatever:'def'},
{GroupByFieldName:'Group 2', whatever:'ghi'},
{GroupByFieldName:'Group 2', whatever:'jkl'},
{GroupByFieldName:'Group 2', whatever:'mno'}
];
$scope.newGrouping = function(group_list, group_by, index) {
if (index > 0) {
prev = index - 1;
if (group_list[prev][group_by] !== group_list[index][group_by]) {
return true;
} else {
return false;
}
} else {
return true;
}
};
}
The output will look like this.
Group 1
- abc
- def
Group 2
- ghi
- jkl
- mno
It feels like there should be a better way. I want this to be a common utility function that I can reuse. Should this be a directive? Is there a better way to reference the previous item in the list than my method of passing the full list and the current index? How would I approach a directive for this?
Any advice is greatly appreciated.
UPDATE: Looking for an answer that does not require external dependencies. There are good solutions using underscore/lodash or the angular-filter module.
Darryl
http://blog.csdn.net/violet_day/article/details/17023219#t2
This is a modification of Darryl's solution above, that allows multiple group by parameters. In addition it makes use of $parse to allow the use of nested properties as group by parameters.
Example using multiple, nested parameters
http://jsfiddle.net/4Dpzj/6/
HTML
Filter (Javascript)
Below is a directive-based solution, as well as a link to a JSFiddle demoing it. The directive allows each instance to specify the field name of the items it should group by, so there is an example using two different fields. It has linear run-time in the number of items.
JSFiddle
The code by JoshMB will not work correctly of you have multiple filters on the same dataset in the same view. The second time you group a filtered version of the dataset, it will change the same attribute in the original object, thus breaking the group breaks in the previously filtered versions.
I solved this by adding the name of the "CHANGED" attribute as en extra filter parameter. Below is my updated version of the code.
EDIT: here's a custom filter approach.
Groups
is created by a filter function in scope to generate array of groups from current list. Adding/deleting list items will bind update of the group array as it is reset every digest cycle.HTML
JS
DEMO
AngularJS has three directives to help you display groups of information. Those directives are ngRepeat, ngRepeatStart and ngRepeatEnd. I found a blog post that shows how show groups in AngularJS. The gist of it is something like this:
Pretty powerful directives once you learn how to use them.