Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

RXJS: Multiple Subscriptions in Order

I’ve searched the web (StackOverflow, Rxjs, blogs, etc.) for an answer to my specific case, but I’ve not found anything for what I’m specifically looking for.

In my Angular component, I have the following:

  ngOnInit(): void {
    this.activatedRoute.queryParams.subscribe((params: any) => {
      if (!!params.page) {
        if (params.page <= 1) this.skip = 0;
        else this.skip = (params.page - 1) * this.limit;
      }
    });
    this.activatedRoute.params.subscribe((params: any) => {
      this.filter = params.filter;
      this.term = params.term;
      this.year = params.year;
      this.month = params.month;
    });
    this.activatedRoute.data.subscribe((data: any) => {
      this.setProvider(data.route);
      this.loadData(data.route);
    });
  }

My problem is I need the queryParams and the params subscriptions to complete and assign the public values before the data subscription takes place (queryParams and params can complete in any order as they don’t have dependencies on each other).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

In all of the examples I’ve seen, they show where each subscription is dependent on the previous and uses the values of the previous (passed down as variables). If I was using pure functions, I could possibly see where this is beneficial, but given that the code-behind in Angular also functions as a ViewModel, I’m simply setting public variables and then referencing them in the setProvider and loadData functions.

The below code works (basically chaining pipes), but given my limited knowledge on all that there is Rxjs, I wasn’t sure if there was a cleaner, more efficient way to write this. It seems rather silly to return an observable just to use its values in the next chain of the pipe.

  ngOnInit(): void {
      this.activatedRoute.queryParams.pipe(concatMap((query: any) => {
        if (!!query.page) {
          if (query.page <= 1) this.skip = 0;
          else this.skip = (query.page - 1) * this.limit;
        }

        return this.activatedRoute.params;
      })).pipe(concatMap((params: any) => {
        this.filter = params.filter;
        this.term = params.term;
        this.year = params.year;
        this.month = params.month;

        return this.activatedRoute.data;
      })).subscribe((data: any) => {
        this.setProvider(data.route);
        this.loadData(data.route);
      });
  }

Thanks everyone!

Edit

The below also works using concat:

  ngOnInit(): void {
    concat(
      this.activatedRoute.queryParams.pipe((q: any) : any => {
        let query = q.getValue();

        if (!!query.page) {
          if (query.page <= 1) this.skip = 0;
          else this.skip = (query.page - 1) * this.limit;
        }
      }),
      this.activatedRoute.params.pipe((p: any) : any => {
        let params = p.getValue();

        this.filter = params.filter;
        this.term = params.term;
        this.year = params.year;
        this.month = params.month;
      }),
      this.activatedRoute.data.pipe((d: any) : any => {
        let data = d.getValue();

        this.setProvider(data.route);
        this.loadData(data.route);
      })
    );
  }

>Solution :

If it has to be done with manual subscriptions I would combine latest for the activatedRoute queryParams, params and data and with a basic if check run the last part when appropriate.

Something like this maybe:

    combineLatest(
      this.activatedRoute.queryParams,
      this.activatedRoute.params,
      this.activatedRoute.data,
      (queryParams: Params, params: Params, data: any) => ({
        queryParams
        params,
        data,
      })
    ).subscribe((res: {queryParams: Params; params: Params; data: any }) => {
     
      if (!!queryParams.page && queryParams.page <= 1) {
       this.skip = 0;
      } else {
        this.skip = (queryParams.page - 1) * this.limit;
      }

     if (params) {
      this.filter = params.filter;
      this.term = params.term;
      this.year = params.year;
      this.month = params.month;
     }

      if (queryParams && params && data) {
        this.setProvider(data.route);
        this.loadData(data.route);
      }
    });

Also try to enforce strong types if possible.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading