1

Using ngrx, I get two data sets from storage.

  private getCatalog() {
    this.catalogStore.select(CatalogStoreSelectors.selectAllCatalogsLoadSuccess)
      .pipe(
        takeWhile(() => this.alive),
        take(1),
        filter(loadSuccess => !loadSuccess),
        tap(() => this.catalogStore.dispatch(new CatalogStoreActions.LoadAllAction())),
      ).subscribe();

    this.catalogs$ = this.catalogStore.select(CatalogStoreSelectors.selectAllCatalogs);
  }

The catalog$ will be Observable<ViewCatalog[]> This is the first data set.

view-catalog.ts

export declare class ViewCatalog {
    code: string;
    title: string;
    lastModified: string;
}

Also for each of the catalog, you can request its items by catalog code

  private getCatalogItems(catalogCode: string) {
    this.catalogStore.dispatch(new CatalogStoreActions.GetCatalogItems({catalogCode: catalogCode}));

    this.catalogItemsStore.select(CatalogItemStoreSelector.selectLoadingByCatalogSuccess)
      .pipe(
        takeWhile(() => this.alive),
        take(1),
        filter(loadSuccess => !loadSuccess),
        tap(() => this.catalogItemsStore.dispatch(new CatalogItemStoreAction.LoadByCatalog({catalogCode: catalogCode}))),
      ).subscribe();

    this.catalogItems$ =  this.catalogItemsStore.select(CatalogItemStoreSelector.selectByCatalogCode(catalogCode));
  }

This is the second data set.

public catalogItems$: Observable<CatalogItem[]>;

CatalogItem.ts

export class CatalogItem {
  constructor(public code: string,
              public catalogCode: string,
              public title: string,
              public data: object) {
  }
}

I need to combine all this data into one common flat list that would look something like this:

[
  catalog: {
    code: "Code 1",
    title: "Catalog title 1",
    lastModifie": "",
    parent: null,
    hasChildren: true
  }
  catalog-item: {
    code: "CatalogItem 1",
    catalogCode: "Code 1",
    parent: "Code 1",
    hasChildren: false,
    title: "CatalogItem title 1"
  },
  catalog-item: {
    code: "CatalogItem 2",
    catalogCode: "Code 1",
    parent: "Code 1",
    hasChildren: false,
    title: "CatalogItem title 2"
  },
  catalog: {
    code: "Code 2",
    title: "Catalog title 2",
    lastModifie": "",
    parent: null,
    hasChildren: true
  },
  catalog-item: {
    code: "CatalogItem 1",
    catalogCode: "Code 2",
    parent: "Code 2",
    hasChildren: false,
    title: "CatalogItem title 1"
  },
  catalog-item: {
    code: "CatalogItem 2",
    catalogCode: "Code 2",
    parent: "Code 2",
    hasChildren: false,
    title: "CatalogItem title 2"
  },
]

Can someone help achieve this?

1 Answers1

0

Heres a simplified example of yours. It uses mocks to mimic catalogues and items fetching.

I've tried to add as much comments as needed.

General idea is to:

  1. fetch all catalogues

  2. for each catalogue fetch its items and then put them into an array with a catalogue

  3. then join all these arrays into one

const { of, combineLatest } = rxjs;
const { delay, switchMap, map } = rxjs.operators;

// 1. fetch all catalogues
// Observable<ViewCatalog[]>
getCatalogues().pipe(
  // chain to fetching items Observables
  switchMap(catalogues => {
    // 2. turn _each catalogue entry_ into
    // [ ViewCatalog, CatalogItem, CatalogItem ... ]
    // results: Observable<(ViewCatalog|CatalogItem)[]>[]
    const results = catalogues.map(
      cat => getItemsForCatalogue(cat.code).pipe(
        // now, merge the ViewCatalog entry
        // with the CatalogItem[] items for this catalogue
        map(items => [cat, ...items])
      )
    ); 

    // 3. use combineLatest to take the latest emissions from the store
    return combineLatest(
      results,
      // and project _each result_ into one array
      // `catsWithItems` here is of type `(ViewCatalog|CatalogItem)[][]`
      (...catsWithItems) => [].concat(...catsWithItems)
    );
  })
)
.subscribe(console.log)


// MOCKS
// getCatalogues(): Observable<ViewCatalog[]>
function getCatalogues(){
  const catalogues =
    [ { code: 1, name: 'cat-1' }
    , { code: 3, name: 'cat-3' }
    , { code: 5, name: 'cat-5' }
    ]

  return of(catalogues).pipe(delay(300));
}

// getItemsForCatalogue(catalogCode: number): Observable<CatalogItem[]>
function getItemsForCatalogue(catalogCode){
  const catalogueItems =
    [ { catalogCode: 1, name: 'item-1' }
    , { catalogCode: 1, name: 'item-2' }
    , { catalogCode: 5, name: 'item-3' }
    ]

  const items = catalogueItems.filter(
      item => item.catalogCode == catalogCode
    );

  return of(items).pipe(delay(300));
}
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>

Hope this helps

kos
  • 5,044
  • 1
  • 17
  • 35