简体   繁体   中英

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?

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]
            };
        })
    }
}

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()
    ); 
  }
}

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],
            };
        })
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM