javascript - portafolio - Cómo hacer un grupo por un filtro en Aurelia
portfolio filter html5 (3)
Estoy buscando la manera de hacer algo como
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>
Es posible de hacer? ¿O cuál es la mejor manera de hacer esta lógica en Aurelia?
Puedes hacer esto usando un 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]
};
})
}
}
Una extensión del ValueConverter anterior que permite usar un filtro de agrupación con propiedades de objetos anidados (por ejemplo, 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],
};
})
}
}
Aún otra extensión que permite especificar como grupo un objeto. Se necesita un segundo parámetro para especificar la clave del objeto que se utilizará como indexador.
p.ej. - | groupBy: ''equipo'': ''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],
};
})
}
}
Después de encontrar esta respuesta, lo hice de una manera ligeramente diferente. En lugar de usar una matriz de objetos con claves de group
y value
, utilicé un Map
.
Vista actualizada
<ul repeat.for="[group, values] of players | groupBy:''team''">
Group name: ${group}
<li repeat.for="player of values">
player: ${player.name}
</li>
</ul>
Para el convertidor de valor, utilicé esta respuesta como inspiración en una forma eficiente de realizar un grupo por operación.
Convertidor de valor
export class GroupByValueConverter {
toView(objects, key) {
return objects.reduce(
(rv, x) => rv.set(x[key], (rv.get(x[key]) || []).concat(x)),
new Map()
);
}
}