I am unable to process the information and transform it into a straightforward list

When using ngrx, I am able to retrieve two distinct 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 of type Observable<ViewCatalog[]>, representing the first data set.

view-catalog.ts

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

Additionally, for each of the catalog entries, it is possible to request its individual items by using the respective 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 represents 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 am looking to merge all this data into a single flat list structure as showcased below:

[
  catalog: {
    code: "Code 1",
    title: "Catalog title 1",
    lastModified: "",
    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",
    lastModified: "",
    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"
  },
]

Assistance on achieving this would be greatly appreciated!

Answer №1

Here is a simplified version that demonstrates the concept. Mocks are used to imitate fetching catalogues and items.

I have included comments throughout the code for clarity.

The main idea is:

  1. Fetch all catalogues

  2. For each catalogue, fetch its items and combine them into an array with the catalogue itself

  3. 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 item Observables
  switchMap(catalogues => {
    // 2. Transform _each catalogue entry_ into
    // [ ViewCatalog, CatalogItem, CatalogItem ... ]
    // Results: Observable<(ViewCatalog|CatalogItem)[]>[]
    const results = catalogues.map(
      cat => getItemsForCatalogue(cat.code).pipe(
        // 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,
      // 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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ddafa5b7ae9debf3e9f3ed">[email protected]</a>/bundles/rxjs.umd.min.js"></script>

I hope you find this explanation helpful.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Connecting a hybrid/web client application to established remote web services outlined through a set of WSDL specifications

Summarizing the Problem I am faced with the task of integrating a mobile hybrid application, likely built on Ionic, that will need to indirectly consume several SOAP web services. My goal is for the TypeScript client in the mobile app to have knowledge of ...

The Disabled element does not exhibit effective styling

When we include the disabled attribute in the text element, the style does not work. Can you explain why? <input pInputText [style]="{'padding-bottom':'10px','padding-top':'10px','width':'100%&apos ...

Problems encountered while trying to install the angular2-meteor package using npm

Attempting to kick off a fresh angular2-meteor project with the command: npm install angular2-meteor --save Encountering a slew of red errors (shown below) and I'm puzzled by their significance. Already executed npm install npm -g and npm ...

Storing an image in MongoDB using Multer as a file from Angular is not working as anticipated

I'm currently dealing with an issue that I believe is not functioning correctly. I installed a library in Angular called cropper.js from https://github.com/matheusdavidson/angular-cropperjs. The frontend code provided by the developer utilizes this li ...

Angular RxJS: The never-ending reduction

I have developed a component that contains two buttons (searchButton, lazyButton). The ngOnDestroy method is defined as follows: public ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } I have created two observables from ...

The act of securing a host connection and actively monitoring it for

Wondering how to incorporate host listeners and host bindings in Angular 2? In my attempts to use a host listener, I encountered an error message indicating "Declaration Expected". Here's what I tried: In the app.component.ts file: import {Componen ...

The DataGrid is only displaying a single result instead of multiple results

I'm having difficulty displaying all the results in this MUI data table. Currently, it is only showing one result instead of all, and I can't figure out what I'm doing wrong. If you have any suggestions or best practices on how to properly ...

Error in React Native Navigation: Passing parameters is not functioning properly

Within my React Native application, I have meticulously established the following routes in my app.js: export default class App extends Component { render() { return ( <NavigationContainer> <Stack.Navigator initialRouteName=&qu ...

Is there a way to transfer innerHTML to an onClick function in Typescript?

My goal is to pass the content of the Square element as innerHTML to the onClick function. I've attempted passing just i, but it always ends up being 100. Is there a way to only pass i when it matches the value going into the Square, or can the innerH ...

Polling database from various browser tabs

Working on a .NET/angular application that regularly checks the SQL Server database for updates, with the user able to customize the polling interval starting from 10 seconds (as per business requirements). The issue arises when each new tab opened by a ...

Exploring the process of authentication and authorization at individual route levels within Angular 4 using Keycloak

We have successfully integrated Keycloak with our application and the login and logout flow is functioning properly. However, we are facing an issue with authentication and authorization at the route level. When a user clears their browser session or the s ...

Integrating one service into another allows for seamless access to the imported service's properties and methods within an Angular

After reviewing the content at https://angular.io/guide/dependency-injection-in-action, it appears that what I am trying to achieve should be feasible. However, I encounter this error when attempting to invoke a method on my injected service from another s ...

Angular Material Progress Spinner is static and not animated

I've been attempting to incorporate an indeterminate spinner from Angular Material. After reviewing the stack blitz example provided on their official website https://stackblitz.com/angular/nkabnxaenep, I carefully compared the package jsons and could ...

Exploring the process of retrieving data from localStorage in Next.js 13

Having recently delved into the realm of Next JS, I've encountered a hurdle when it comes to creating middleware within Next. My aim is to retrieve data from local storage, but I keep hitting roadblocks. middleware.ts import { key, timeEncryptKey, to ...

Is it not possible to call this authentication expression in a Typescript file when using Next JS?

I am currently developing a sign-in method for my Next.js application and I have been referring to the GitHub repository's recommended documentation. However, upon reaching the authentication folder step, I encountered an error regarding the sign-in ...

Is there a simple method I can use to transition my current react.js project to typescript?

I am currently working on a project using react.js and am considering converting it to typescript. I attempted following an article on how to make this conversion but have run into numerous bugs and issues. Is there a simpler method for doing this conver ...

The ngx-image-cropper's roundCropper attribute is not functioning correctly as it should. An error is being displayed stating: "Type 'string' is not assignable to type 'boolean'"

<image-cropper [imageChangedEvent]="imageChangedEvent" [maintainAspectRatio]="true" [aspectRatio]="4 / 4" format="jpg" (imageCropped)="imageCropped($event)" roundCropper = "true"> </i ...

Tips for eliminating a port from an Angular 2 URL

Whenever I launch an angular2 project, it automatically includes localhost:4200 in the URL, even after deploying it on a server. Is there a way to remove the port number from the URL without making changes to the core files? I attempted to modify the pac ...

Cypress eliminating the "X-CSRFToken" header

There seems to be an issue with the Cypress test runner where it is removing X-CSRFToken from the request header, leading to a 403 Forbidden error. I have compared the headers between a manual run and a Cypress test run, and you can see the difference in t ...

Encountering the error message "This expression cannot be invoked" within a Typescript React Application

I'm working on separating the logic from the layout component in my Typescript React Application, but I suspect there's an issue with the return type of my controller function. I attempted to define a type to specify the return type, but TypeScr ...