Угловая древовидная структура с двумя разными списками, заполняемыми из вложенной подписки rxjs

В 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 раз.

Я знаю, что было бы намного проще, если бы таблица в базе данных была связана с помощью внешнего ключа и плоского списка, но я не могу это контролировать.

Любая помощь или предложение приветствуется. Спасибо!

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
0
367
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Введя состояние, ваше решение стало очень сложным.

Попробуй это

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

Внутри подписки вы получите массив напрямую.

Несмотря на свою итерацию nxm, ваш код намного чище. Я не был знаком с conCatmap. Я проверил ваш код, и он работает как шарм. Просто изменил метод toArray(), потому что это опечатка. Кроме того, он мне не нужен, так как я получаю значение непосредственно внутри подписки. Спасибо

Asif Rahman 31.05.2019 14:02

Почему вам не понадобится toArray(), потому что в вашем вопросе окончательный ответ - это что-то вроде массива, верно? Также, если решение сработало, вы можете отметить его как принятое. Рад помочь.

emkay 31.05.2019 21:42

Другие вопросы по теме