0

I have a function A and B. I want both these functions to run at the initial of the component load, on ngOnInit, but B should run only after the completion of A. Coz for B to run, i will need values from A. For this, I kept B inside A. A has observables. Hence the subscriptions is getting called two times, navigate to different page and come back again, its getting called 3 times and so on. I have two different objects, say data:any and array1 that needs to be filled up in A's code.

Example A code:

ngOnInit(){
    A();
}

A(){
    this.service1.getData().subscribe((resp)=>
        if(resp){
            //some logic
            this.service2.dataFor.pipe(skipWhile((val)=>val ===null )).subscribe((response)=>{
            //some logic to fill up data and array1 from the subscribed data
            })
        }
    )
}


B(){
    if(this.data && Object.keys(this.data).length>0){
        this.service3.getValidity(this.data.data).subscribe((resp)=>{
        if(resp){
            //some code
            console.log("from B if");

        }
        
        else if(this.array1.length===0){
            this.service3.getValidity('').subscribe((res)=>{
                //some logic
                console.log("from B else");
            })
        }
        })
    }
}

For now what I am doing is calling B() inside A(), something like:

A(){

    this.service1.getData().subscribe((resp)=>
        if(resp){
            //some logic
            this.service2.dataFor.pipe(skipWhile((val)=>val ===null )).subscribe((response)=>{
            //some logic to fill up data and array1 from the subscribed data
            
            console.log("from A ");
            B();
            //after data and array1 has data
            })
        }
    )
}

What this does is calls subscriptions multiple times and At first displays from B if two times, if I navigate to another page and come back to this page again, it displays 3 times, similarly 4,5,6... times.

I thought not unsubscribing the subscriptions may have caused this, so on

ngOnDestroy(){
     //unsubscribed all the subscriptions
}

full code for reference:

A(){
    this.subscription1=this.service1.getData().subscribe((resp)=>
        if(resp){
            //some logic
            this.subscription2=this.service2.dataFor.pipe(skipWhile((val)=>val ===null )).subscribe((response)=>{
            //some logic to fill up data and array1 from the subscribed data
            
            B();
            //after data and array1 has data
            })
        }
    )
}


B(){
    if(this.data && Object.keys(this.data).length>0){
        this.subscription3=this.service3.getValidity(this.data.data).subscribe((resp)=>{
        if(resp){
            //some code
        }
        
        else if(this.array1.length===0){
            this.service3.getValidity('').subscribe((res)=>{
                //some logic
            })
        }
        })
    }
}


ngOnDestroy() {
    if (this.subscription1 && !this.subscription1.closed) {
      this.subscription1.unsubscribe();
    }
    if (this.subscription2 && !this.subscription2.closed) {
      this.subscription2.unsubscribe();
    }
    if (this.subscription3 && !this.subscription3.closed) {
      this.subscription3.unsubscribe();
    }
  }

This didnt work either.

I think the nested function calls, B() inside A() is causing this.

I want A() to complete storing the values in data and array1 and then only B() should run.

How do I achieve this in an efficient way? and without subscriptions being called multiple times.

  • > 'I thought not unsubscribing the subscriptions may have caused this, so on', can you please append the code reference for unsubscribe too? I count 4 subscriptions, did you unsubscribe to all the 4? (2 (top level subscribes)at the least). – chandresh_n Mar 30 '22 at 12:11

1 Answers1

0

Instead of subscribing, you could could use firstValueFrom (https://rxjs.dev/api/index/function/firstValueFrom) which is returning a Promise from a Observable. Then you can simply await the promise, which resolves only once.

import { firstValueFrom, map } from 'rxjs';

async ngOnInit() {
    const response = await firstValueFrom(A());
    B(response);
}
A() {
    return this.service1.getData().pipe(
        map((resp) => {
            return; //do something with the response
        })
    );
}

Seega
  • 3,001
  • 2
  • 34
  • 48
  • Module '"rxjs"' has no exported member 'firstValueFrom'. i get this – AngularEnthusiast Mar 30 '22 at 12:56
  • Do you have rxjs in your dependencies? If so, firstValueFrom was added in the latest version. – Seega Mar 30 '22 at 13:16
  • Alternatively, you could use ``await A().toPromise()``which was the previous way to do it. – Seega Mar 30 '22 at 13:17
  • I probably dont have the latest and its a corporate code, so i cant add a newer version for now, even for map its showing up the same, what would i have to change in function A() for that – AngularEnthusiast Mar 30 '22 at 13:21
  • You can use ``await this.service2.dataFor.pipe(skipWhile((val)=>val ===null )).toPromise()`` which will run the code synchronous afterwards. Just make sure to write `async` in front of your function declarations as well. – Seega Apr 06 '22 at 20:59