The significance of sequence in Angular2 Observable handling

When dealing with observables in a component that makes multiple API calls using a service, is there a way to ensure that one observable completes before another starts?

For example, how can we make sure that the getOptions function finishes executing before the getReport function is triggered? The getReport function depends on data obtained by getOptions.

  ngOnChanges() {
    if (this.treeResult != null) {              
      for (var index = 0; index < this.treeResult.length; index++) {        
        var element = this.treeResult[index];               
          this.thumbnailView = null;

          this.getOptions(element.id);            

          this.getReport(element.id, this.a, this.b, element.c);              
      }
    }
  }

  getOptions(id: number) {
    this._Service.GetOptions(id)
      .subscribe(options => { this.select = options[0].Options1, this.num = options[0].Options1[0].optionId,
                              error => this.errorMessage = <any>error)
  }  

  getReport(id: number, a: number, b: number, c: string) {
    this._Service.GetReport(id, a, b, c)
      .subscribe(data => { this.data = data }, error => this.errorMessage = <any>error);
  }

If you need more information or clarification, feel free to ask!

Answer №1

A solution is to invoke the second observable inside the done() function of the first one:

 ngOnChanges() {
    if (this.treeResult != null) {              
      for (var index = 0; index < this.treeResult.length; index++) {        
        var element = this.treeResult[index];               
          this.thumbnailView = null;

          this.fetchOptions(element.id, element.c);                       
      }
    }
  }

  fetchOptions(id: number, c : any) {
    this._Service.GetOptions(id)
      .subscribe(options => { 
              this.select = options[0].Options1;
              this.num = options[0].Options1[0].optionId;
          }, error => {
              this.errorMessage = <any>error;
          }, () => {
              // done
              this.retrieveReport(id, this.a, this.b, c);
          });
  }  

  retrieveReport(id: number, a: number, b: number, c: string) {
    this._Service.GetReport(id, a, b, c)
      .subscribe(data => { 
               this.data = data;
          }, error => {
              this.errorMessage = <any>error;
          }, () => {
              // done
          });
  }

Answer №2

To run observables in sequence, you can make use of the flatMap operator.

Below is an example demonstrating how to implement it within your scenario:

  ngOnChanges() {
    if (this.treeResult != null) {              
      this.treeResult.forEach(element => {
        this.thumbnailView = null;

        this.getOptions(element.id).flatMap(() => { // <------
          this.getReport(element.id, this.a, this.b, element.c);
        }).subscribe();
      });
    }
  }

  getOptions(id: number) {
    return this._Service.GetOptions(id)
      .map(options => { // <-----
        this.select = options[0].Options1;
        this.num = options[0].Options1[0].optionId
      })
      .catch(error => this.errorMessage = <any>error);
  }  

  getReport(id: number, a: number, b: number, c: string) {
    return this._Service.GetReport(id, a, b, c)
      .map(data => {
        this.data = data;
      })
      .catch(error => this.errorMessage = <any>error);
  }

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

The PrimeNg confirmDialog is updating my navbar with some modifications

Despite my navbar working well and being fully responsive, I encountered an issue where opening a confirm dialog in the background caused the navbar width to expand to 800px even though the screen width was 1480px, creating empty space on the right side, a ...

trpc - Invoking a route from within its own code

After reviewing the information on this page, it appears that you can invoke another route on the server side by utilizing the const caller = route.createCaller({}) method. However, if the route is nested within itself, is it feasible to achieve this by ...

What is the method for showing the number of characters in a string within a textfield by utilizing events in Angular

I have been working on a project that requires me to calculate and display the length of a string entered into a text field using Events. There is an additional condition where the string length must be greater than 4 in order for the length to be displaye ...

Steps for creating a copy of an Angular component

https://i.stack.imgur.com/4RMsR.png Whenever the user clicks on the Create Copy button, I aim to replicate the content of the DashboardComponent and position the duplicated version below the original one (the DashboardComponent featuring four dark blue sq ...

Deactivate the next button on the paginator within the PrimeNG p-table

In the p-table paginator, I want to disable the next button when a specific boolean is set to false. Below is my p-table setup: <p-table #dt id="{{id}}_table" [(value)]="_datasrc" [columns]="cols" [rows]="rowNumber || ...

The use of supportedChain is no longer recommended, networks should be passed instead

As I reach the final lesson, an error message appears in my localhost console: The 'supportedChain' is deprecated, please pass networks instead useConfig @ context.ts:23 Initially, I suspected it was a problem with my code. However, even after c ...

Angular - Loading images on demand

I've recently started learning Angular and Typescript, and I've run into an issue that I could use some help with. I want to implement lazy loading for all the images in my application by adding the loading="lazy" attribute to each < ...

The Angular frontend is failing to receive the expected response when making an http request to the Express backend

I'm currently working with Angular 7 to send an HTTP request to an Express 4 backend code, however I keep encountering a 404 response. I suspect that the issue lies in how I've specified the path for the HTTP request, but I'm not entirely ce ...

Encountering an issue with accessing a property in Angular's TypeScript module

I encountered an issue while trying to access a property of a static array that I created in a TypeScript class. The error message I received is as follows: ERROR TypeError: Cannot read property 'forbiddenProjectNames' of undefined Below is th ...

Maintain the variable name when using destructuring in JavaScript/TypeScript

Can variable names and destructuring be used together in a single command in JavaScript/TypeScript? For example: function stopTheCar(car & { speed } : Car) { if (speed > 10) car.stop() } The closest option available is to use destructuring in a ...

Vue: rendering props cannot be utilized with TSX

After switching my setup from JSX in a Vue component to TS with vue-class-component, I found that only the code snippet below works for me (as shown in the example on repo): import Vue from 'vue' import { Component } from 'vue-property-dec ...

The constant value being brought in from an internal npm package cannot be determined

I have developed an internal npm package containing shared types and constants. My project is built using TypeScript with "target": "ESNext" and "module": "NodeNext". Within one of my files, I define: export type Su ...

Using Angular 2 to pass @Input values from a dropdown selection

I'm encountering an issue when trying to pass the @input parameter from the parent component. My goal is to create cascading dropdowns, with one in the parent component and one in the child. Upon selecting an option in the parent dropdown, I want to d ...

Are the Angular App routerlinks functioning properly in development but encountering issues in the production environment?

Every time I execute the command npm start, my Angular application works perfectly as intended. However, when I attempt to build it in "prod" mode, my application doesn't seem to function properly. It only displays a static page. All navigation link ...

What is the best way to update an array in TypeScript when the elements are of different types and the secondary array has a different type as

const usersData = [ { "id": 0, "name": "ABC" }, { "id": 1, "name": "XYZ" } ]; let dataList = []; // How can I transfer the data from the user array to the dataList array? // If I use the map function, do I need to initialize empty values for oth ...

Utilizing closure to implement a counting mechanism within a function

Every time I attempt this, it only displays once and seems to be incorrect. Is there a way to resolve the issue? function myFunc() { var increment = (function() { var i = 0; return function() { i++; ...

Exploring TypeScript: TS2349 - The function you are trying to call is not callable. The type 'never' does not have any call signatures

Currently, I am delving into typescript and attempting to integrate it into an existing vue3-project. Here is the previous mixin-method: export const promises = { methods: { async process(...args): Promise<unknown> { return ...

The imported symbol from the typescript library cannot be found

Currently, I am in the process of developing a React/Redux application using Typescript. My goal is to streamline development by creating libraries for each unique "domain" or "feature" that will contain domain-specific details and provide an API to the ma ...

Tips for validating a form with a condition in Angular 6

I have a dropdown menu where the selected option determines which additional columns are displayed alongside the common columns. How can I validate the form without separate form control names? My html: <mat-form-field class="col-xl-6 col-lg-3 col-md- ...

Is there a way to retrieve the index and specific object that was modified using $watch in Angular?

I am receiving an array of objects from an API that is being updated every 2 seconds. I have a $watch function that is monitoring any changes in this array. I want to be able to identify which elements have changed along with their index, so that I can dyn ...