angularangular2-observablesrxjs-observables

can I call the apis in observable in a certain sequence/order


I am learning angular Observable topic. I was trying to call apis inside Observable and hoping that they will run in an order in which I have stated them.

Below is my component class code:

import { HttpClient } from '@angular/common/http';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-flav4',
  templateUrl: './flav4.component.html',
  styleUrls: ['./flav4.component.css']
})
export class Flav4Component implements OnInit, OnDestroy {
  orderStatus!: any;
  data!: Observable<any>;
  constructor(private httpcli: HttpClient) { }
  ngOnInit(): void {
    this.data = new Observable(observer => {
      this.httpcli.get("http://localhost:9898/api/orderStart", { headers: { "content-type": "application/json" } }).subscribe(data => {
        console.warn(data);
        this.orderStatus = data;
        observer.next(this.orderStatus);

      });
      this.httpcli.get("http://localhost:9898/api/orderWait", { headers: { "content-type": "application/json" } }).subscribe(data => {
        console.warn(data);
        this.orderStatus = data;
        observer.next(this.orderStatus);

      });
      this.httpcli.get("http://localhost:9898/api/orderComplete", { headers: { "content-type": "application/json" } }).subscribe(data => {
        console.warn(data);
        this.orderStatus = data;
        observer.next(this.orderStatus);

      });
    });
    this.data.subscribe(val => this.orderStatus = val);
  }
  ngOnDestroy(): void {
  }
}

I was expecting console output to be

{"status": "orderStarted"}
{"status": "orderWaiting"}
{"status": "orderCompleted"}

However I got below output

{"status": "orderStarted"}
{"status": "orderCompleted"}
{"status": "orderWaiting"}

What should I change in this code in order to get desired output i.e to run APIs in a certain order or sequence.


Solution

  • This is normal behaviour as HTTP requests are asynchronous.

    You can try chaining them with mergeMap also known as flatmap from RxJS library. I suggest you take a look at the behaviours as well.

    Something like this as reference

    import { HttpClient } from '@angular/common/http';
    import { Component, OnDestroy, OnInit } from '@angular/core';
    import { Observable } from 'rxjs';
    import { mergeMap } from 'rxjs/operators';
    
    @Component({
      selector: 'app-flav4',
      templateUrl: './flav4.component.html',
      styleUrls: ['./flav4.component.css']
    })
    export class Flav4Component implements OnInit, OnDestroy {
      orderStatus!: any;
      data!: Observable<any>;
      constructor(private httpcli: HttpClient) { }
      ngOnInit(): void {
        this.data = this.httpcli.get("http://localhost:9898/api/orderStart", { headers: { "content-type": "application/json" } }).pipe(
          mergeMap(orderStart => {
            console.warn(orderStart);
            this.orderStatus = orderStart;
            return this.httpcli.get("http://localhost:9898/api/orderWait", { headers: { "content-type": "application/json" } });
          }),
          mergeMap(orderWait => {
            console.warn(orderWait);
            this.orderStatus = orderWait;
            return this.httpcli.get("http://localhost:9898/api/orderComplete", { headers: { "content-type": "application/json" } });
          })
        );
        this.data.subscribe(orderComplete => {
          console.warn(orderComplete);
          this.orderStatus = orderComplete;
        });
      }
      ngOnDestroy(): void {
      }
    }