I need to have my data in a form like this to be able to do 2 nested ngFor
loops:
this.groupedCities = [
{
label: 'Germany', value: 'de',
items: [
{label: 'Berlin', value: 'Berlin'},
{label: 'Frankfurt', value: 'Frankfurt'},
{label: 'Hamburg', value: 'Hamburg'},
{label: 'Munich', value: 'Munich'}
]
},
{
label: 'USA', value: 'us',
items: [
{label: 'Chicago', value: 'Chicago'},
{label: 'Los Angeles', value: 'Los Angeles'},
{label: 'New York', value: 'New York'},
{label: 'San Francisco', value: 'San Francisco'}
]
},
];
But my back end only supplies it like this:
this.data = [
{label: 'Berlin', value: 'Berlin', country: 'Germany'},
{label: 'Frankfurt', value: 'Frankfurt', country: 'Germany'},
{label: 'Hamburg', value: 'Hamburg', country: 'Germany'},
{label: 'Munich', value: 'Munich', country: 'Germany'}
{label: 'Chicago', value: 'Chicago', country: 'USA'},
{label: 'Los Angeles', value: 'Los Angeles', country: 'USA'},
{label: 'New York', value: 'New York', country: 'USA'},
{label: 'San Francisco', value: 'San Francisco', country: 'USA'}
];
I seem to remember a way to do this in rxjs but I can't remember it.
CodePudding user response:
You could achieve this by a combination of these RxJS operators
import { from } from 'rxjs';
import { groupBy, mergeMap, reduce, toArray } from 'rxjs/operators';
const mapper = {
'Germany': 'de',
'USA': 'us'
};
const data$ = from([
{label: 'Berlin', value: 'Berlin', country: 'Germany'},
{label: 'Frankfurt', value: 'Frankfurt', country: 'Germany'},
{label: 'Hamburg', value: 'Hamburg', country: 'Germany'},
{label: 'Munich', value: 'Munich', country: 'Germany'},
{label: 'Chicago', value: 'Chicago', country: 'USA'},
{label: 'Los Angeles', value: 'Los Angeles', country: 'USA'},
{label: 'New York', value: 'New York', country: 'USA'},
{label: 'San Francisco', value: 'San Francisco', country: 'USA'}
]);
const grouped$ = data$.pipe(
groupBy(city => city.country),
mergeMap(group => group
.pipe(
reduce((acc, cur) => {
const item = {label: cur.label, value: cur.value};
acc.items.push(item);
return acc;
},
{ key: group.key, value: mapper[group.key], items: [] }
)
)
),
toArray()
);
grouped$.subscribe(console.log);
Demo: https://playcode.io/976662
CodePudding user response:
Hope this helps; I notice there is no key for abbr for the country code
const partition = (arr, fn) =>
arr.reduce(
(acc, val, i, arr) => {
acc[fn(val, i, arr) ? 0 : 1].push(val);
return acc;
},
[[], []]
);
let data = [
{label: 'Berlin', value: 'Berlin', country: 'Germany'},
{label: 'Frankfurt', value: 'Frankfurt', country: 'Germany'},
{label: 'Hamburg', value: 'Hamburg', country: 'Germany'},
{label: 'Munich', value: 'Munich', country: 'Germany'},
{label: 'Chicago', value: 'Chicago', country: 'USA'},
{label: 'Los Angeles', value: 'Los Angeles', country: 'USA'},
{label: 'New York', value: 'New York', country: 'USA'},
{label: 'San Francisco', value: 'San Francisco', country: 'USA'}
];
const [germany, nonGermany] = partition(data, o=> o.country === 'Germany').map((arr) =>{
return arr.reduce((acc, cv, i) => {
if(i === 0){
acc = {...acc, label: cv.country, value: '', items: [{label: cv.label, value: cv.value}]}
return acc
}
return {
...acc,
items:[
...acc.items,
{label: cv.label, value: cv.value}
]
};
}, {})
});
console.log(germany);
console.log(nonGermany);