0

I want to make two HTTP calls.

Below is my TypeScript Code

   CheckLogIn() {
    this.http.get<boolean>(this.baseUrl + 'api/LogIn/CheckLogIn/' + this.StaffCode).subscribe(result => {
      setTimeout(() => {
        if (result == true) {
          this.GetUserName();
          sessionStorage.setItem("UserID", this.StaffCode);
          this.router.navigate(['/log-tracker']);
        }
      }, 5000)
    }, error => console.log(error));
  }

 GetUserName() {
    this.http.get(this.baseUrl + 'api/Common/GetUserName/' + sessionStorage.getItem("UserID"), { responseType: 'text' }).subscribe(result => {
      console.log(result);
      sessionStorage.setItem("UserName", result);
    }, error => console.log(error));
  }

Here Inside CheckLogin() I am calling an endpoint and within response of this call I am invoking another one (GetUserName) and then redirecting to another page.

But checkLogin Does not wait for GetUserName to finish and redirect to page before second call finishes its work , hence session username is always null .

I tried using SetTimeout Function but it does not work here , is there any other way to put a delay before redirection , or any way to make first call wait until second call finishes its work ?

7
  • I edit your question because you're not using two APIs. Commented Aug 9, 2018 at 7:30
  • this.router.navigate(['/log-tracker']); this has to be within GetUserName subscribe method. Commented Aug 9, 2018 at 7:30
  • use switchMap Commented Aug 9, 2018 at 7:30
  • @trichetriche , thanks , but look again , hope you will find both api's Commented Aug 9, 2018 at 7:33
  • @SujataChanda , I will try that idea Commented Aug 9, 2018 at 7:33

2 Answers 2

2

You're not waiting for GetUserName within CheckLogin you're just calling it and ignoring the result. You could try returning the observable from GetUserName - and there's also a good opportunity here to use other RXJS operators.

import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/do';

CheckLogIn() {
  this.http.get<boolean>(this.baseUrl + 'api/LogIn/CheckLogIn/' + this.StaffCode)
    .filter(result => result)
    .do(() => sessionStorage.setItem("UserID", this.StaffCode))
    .mergeMap(() => this.GetUserName())
    .subscribe( // This does not execute until the observable from GetUserName is complete
       result => this.router.navigate(['/log-tracker']),
       error => console.log(error)
    );
}

GetUserName() { // I now return an observable
  return this.http.get(this.baseUrl + 'api/Common/GetUserName/' + sessionStorage.getItem("UserID"), { responseType: 'text' })
    .do(result => sessionStorage.setItem("UserName", result));
}

Now we do the following:

  1. Call CheckLogin
  2. If result is true, continue
  3. Set UserID in session storage
  4. Call GetUserName and replace our observable with it
  5. When the observable returned by GetUserName completes we can navigate

There's no need to replace RXJS with promises, it has a lot of power when you're doing asynchronous requests - it especially shines in cases such as this when you have multiple calls to do in a certain order, and conditions that have to be met.

Sign up to request clarification or add additional context in comments.

8 Comments

.mergeMap(this.GetUserName()) this wont work without binding.
What do you mean? Without calling .bind on it? It surely will, we are still in the context of the class at this point, so this should be as we expect it to be.
Wait sorry, you actually did the invocation - i read it as function pass - my bad.
Now that you mention it however, I believe it should be a function rather than just an invocation of GetUserName, but using an arrow function should prevent loss of this context,
@Jack I've created a very rough example at stackblitz.com/edit/angular-utzj3i you can see that the API calls do occur and the navigation happens. Are you sure you're calling the CheckLogIn method? @Antoniossss as I understand it pipe exists to allow for easier re-use of code, which isn't very relevant here. I understand the argument that one import is less than three, but I think you'd still end up importing filter which makes it hardly worth the effort and in my opinion reduction in readability.
|
1

You can use Promise

CheckLogIn() {
  try {
    return new Promise((resolve, reject) => {
      this.http.get<boolean>(this.baseUrl + 'api/LogIn/CheckLogIn/' + this.StaffCode).subscribe(result => {
        setTimeout(() => {
          if (result == true) {
            this.GetUserName();
            sessionStorage.setItem("UserID", this.StaffCode);
            this.router.navigate(['/log-tracker']);
          }
        }, 5000)
      }, error => console.log(error));
      resolve();
    })
  } catch (error) {
    console.log(error);
  }
}

Call your Checklogin function Like this

this.CheckLogIn().then(()=>{
      this. GetUserName();
    });

1 Comment

There's no need to wrap an observable in a promise. Observables have all the functionality of promises and more.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.