Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do group by filter in Aurelia

I'm looking way to do something like

JS

$scope.players = [
  {name: 'Gene', team: 'alpha'},
  {name: 'George', team: 'beta'},
  {name: 'Steve', team: 'gamma'},
  {name: 'Paula', team: 'beta'},
  {name: 'Scruath', team: 'gamma'}
];

HTML:

<ul repeat.for="obj of players | groupBy: 'team'">
  Group name: ${obj.group}
  <li repeat.for="player of obj.values">
    player: ${player.name} 
  </li>
</ul>

Is it possible to do? Or what the better way to do this logic in Aurelia way?

like image 637
Egor Malkevich Avatar asked Mar 03 '16 13:03

Egor Malkevich


People also ask

How do I create group filters in Oracle Database?

Click Menu, and then select Create Group Filter. Select the Group Filter Type: Expression or PL/SQL. For PL/SQL filters, ensure that you specify the PL/SQL Package as the Oracle DB Default Package in the data model properties. To enter an expression, select the elements and move the elements to the Group Filter definition box.

How can I observe changes in an array in Aurelia?

To ensure that Aurelia can observe the changes on your array, make use of the Array methods: Array.prototype.push, Array.prototype.pop and Array.prototype.splice. Two-way binding with arrays requires a special syntax due to the nature of the for-of loop in javascript.

Does Aurelia slow down as you add more functionality?

This means that Aurelia doesn't slow down as you add more complex functionality to your template and view-model. Binding in Aurelia allows data from the view-model to drive template behavior.

Is there any dirty-checking in Aurelia?

But don't worry, there is no dirty-checking. Aurelia uses an observable-based binding system that reacts to changes as they happen without having to do dirty-checking. This means that Aurelia doesn't slow down as you add more complex functionality to your template and view-model.


3 Answers

You can do this using a ValueConverter.

export class GroupByValueConverter {
    toView(array, groupBy) {

        var groups = {};

        array.forEach(function (o) {
            var group = o[groupBy];
            groups[group] = groups[group] || [];
            groups[group].push(o);
        });

        return Object.keys(groups).map(function (group) {
            return {
                group: group,
                values: groups[group]
            };
        })
    }
}
like image 62
Leo Avatar answered Oct 24 '22 03:10

Leo


After finding this answer, I did it in a slightly different way. Instead of using a an array of objects with group and value keys, I used a Map.

Updated view

<ul repeat.for="[group, values] of players | groupBy:'team'">
  Group name: ${group}
  <li repeat.for="player of values">
    player: ${player.name} 
  </li>
</ul>

For the value converter I used this answer for inspiration on an efficient way to perform a group by operation.

Value Converter

export class GroupByValueConverter {
  toView(objects, key) {
    return objects.reduce(
      (rv, x) => rv.set(x[key], (rv.get(x[key]) || []).concat(x)), 
      new Map()
    ); 
  }
}
like image 42
Dave Jensen Avatar answered Oct 24 '22 03:10

Dave Jensen


An extension to the ValueConverter above allowing to use a grouping filter with nested object properties (eg. groupBy:'team.id')

export class GroupByValueConverter {
    toView(array, groupBy) {

        var groups = {};
        var props = groupBy.split(".");

        array.forEach(function (o) {
            var group = o;
            props.forEach(function (p) { group = group[p] });
            groups[group] = groups[group] || [];
            groups[group].push(o);
        });

        return Object.keys(groups).map(function (group) {
            return {
                group: group,
                values: groups[group],
            };
        })
    }
}

Yet another extension that allows to specify as group an object. It takes a second parameter for specifying the object key to be used as indexer.

eg. - | groupBy:'team':'id' - | groupBy:'projectMember.team':'id'

export class GroupByValueConverter {
    toView(array, groupBy, groupByKey) {

        var groups = {};
        var groupMembers = {};
        var props = groupBy.split(".");

        array.forEach(function (o) {
            var group = o;
            props.forEach(function (p) { group = group[p] });
            var index = groupByKey && group ? group[groupByKey] : group;
            groups[index] = group;
            groupMembers[index] = groupMembers[index] || [];
            groupMembers[index].push(o);
        });

        return Object.keys(groups).map(function (index) {
            return {
                group: groups[index],
                values: groupMembers[index],
            };
        })
    }
}
like image 38
Kathleen Avatar answered Oct 24 '22 03:10

Kathleen