В Angular 7 у меня есть два наблюдаемых, которые получают данные с сервера; Observables дает следующие списки:
productgroup = [{"id":"1","groupname":"gr1"},{"id":"2","groupname":"gr2"}];
products = [{"id":"1","productname":"COMPUTER","productgroup":"gr2",....},{"id":"2","productname":"ACCESSORIES","productgroup":"gr1",....}]
Мне нужно создать древовидную структуру данных, чтобы создать меню с угловым деревом материалов, например следующее:
[
{
"id":1,
"name": "gr1",
"children": [
{"id":"1","productname":"COMPUTER","productgroup":"gr2",....},
{"id":"2","productname":"ACCESSORIES","productgroup":"gr1",....}
]
}
{
}
]
Код, который я пробовал, выглядит следующим образом:
this.productGroupService.getAll().pipe(switchMap((allgroup: any) => {
var flag = 0;
this.groups = []; // array to hold group or parent data
allgroup.map(element => {
this.finalarr = []; // fial array
console.info(element.id);
this.productService.getbygroup(element.id)// for each group getting product data list
.pipe(map((data) => {
this.productInGroup[flag] = []; // array to hold children data
this.groups.push(element);
data.map((dval)=>{
this.productInGroup[flag].push({productname: dval["productname"], id: String(dval["id"])});
})
flag++;
})
).subscribe((data) => {
if (allgroup.length == flag){
//console.info(this.groups);
var flag2 = 0;
this.groups.map(()=>{
var obj = {groupname: this.groups[flag2].groupname,id:this.groups[flag2].id,
products:this.productInGroup[flag2]}; // joining child and parent data into single object
this.finalarr.push(obj);
flag2++;
if (flag2 == this.groups.length){
this.datasource = this.finalarr;
console.info(this.datasource);
}
})
}
})
});
})).subscribe()
Сначала я перебираю список групп продуктов и создаю родительский массив. Затем для каждой группы я получаю данные с сервера по подписке и создаю дочерний массив. Затем создайте объект с этим массивом и поместите его в окончательный массив.
Код работает для небольшого набора данных. Но я не доволен этим решением поскольку он перебирает все продукты для всех групп nxm раз.
Я знаю, что было бы намного проще, если бы таблица в базе данных была связана с помощью внешнего ключа и плоского списка, но я не могу это контролировать.
Любая помощь или предложение приветствуется. Спасибо!
Введя состояние, ваше решение стало очень сложным.
Попробуй это
const productGroup$ = this.productGroupService.getAll();
productGroup$.pipe(
mergeMap((productGroupArray) => from(productGroupArray)),
concatMap(
(productGroupItem) => this.productService.getbygroup(productGroupItem.id).pipe(
map((product) => {
let json = {};
json['id'] = productGroupItem.id;
json['name'] = productGroupItem.groupname;
json['children'] = product;
return json;
})
)),
toArray()
).subscribe((val) => console.info(val));
Внутри подписки вы получите массив напрямую.
Почему вам не понадобится toArray(), потому что в вашем вопросе окончательный ответ - это что-то вроде массива, верно? Также, если решение сработало, вы можете отметить его как принятое. Рад помочь.
Несмотря на свою итерацию nxm, ваш код намного чище. Я не был знаком с conCatmap. Я проверил ваш код, и он работает как шарм. Просто изменил метод toArray(), потому что это опечатка. Кроме того, он мне не нужен, так как я получаю значение непосредственно внутри подписки. Спасибо