I have an http
observable like so, in my UserService
:
logout() {
return this.http.delete(this.baseUrl + url, {
headers: this.headers()
}).map((res: IResponse) => {
var json = res.json();
json.headers = res.headers;
return json;
}).subscribe((response) => {
//DO SOMETHING, THEN ----
return res;
});
}
I have created an observable, and created a subscription (response
) which is the returned success value.
Now, in my component, I want to call UserService.logout()
and THEN navigate to a new route:
logout() {
this.userService.logout();
this.router.navigate(['LandingPage']);
}
Obviously, this could happen asynchronously and I may end up navigating before I logout.
Using promises, I could do something like this:
this.userService.logout().then(() => {
this.router.navigate(['LandingPage']);
});
How can I do the same thing with observables? In my UserService
class I want to create an observable, subscribe to it, do some stuff on success or on error, THEN navigate from my view component.
You can actually make logout
method return a promise and use it as normal. It doesn't have to be Observable:
logout() {
return new Promise((resolve, reject) => {
this.http.delete(this.baseUrl + url, { headers: this.headers() })
.map((res: IResponse) => {
var json = res.json();
json.headers = res.headers;
return json;
})
.subscribe(data => {
//DO SOMETHING, THEN ----
resolve(data);
}, error => reject(error));
});
}
logout() {
this.userService.logout().then(response => this.router.navigate(['LandingPage']))
}
Observable object has method finally, try it.
Don't forget to import first:
import 'rxjs/operators/finally';
Your logout() would be:
logout() {
return this.http.delete(this.baseUrl + url, { headers: this.headers() })
.map(res => res.json())
.finally(() => this.router.navigate(['LandingPage']))
.subscribe((response) => {
//DO SOMETHING, THEN ----
});
}
If you really wanted to use promise:
import 'rxjs/add/operator/toPromise';
logout() {
return this.http.delete(this.baseUrl + url, { headers: this.headers() })
.map(res => res.json());
in component.ts
var aPromise = this.userService.logout().toPromise();
aPromise.then(() => {
this.router.navigate(['LandingPage']);
});
You can't wait for an Observable
to finish because its stream might continue indefinitely. But you could call router.navigate
inside the subscribe
method:
logout() {
return this.http.delete(this.baseUrl + url, { headers: this.headers() })
.map((res: IResponse) => res.json())
.subscribe((response) => {
//DO SOMETHING, THEN ----
this.router.navigate(['LandingPage']);
});
}
If this isn't sufficient, subscribe
returns a Subscription
whose unsubscribe
method stops waiting for the Observable
's data. So if you have to, you can wait for a timeout period and call unsubscribe
.
Logout need to return an Observable not a Subscription.
For example:
logout(): Observable<T> {
return this.http.delete(this.baseUrl + url, {
headers: this.headers()
}).map((res: IResponse) => {
var json = res.json();
json.headers = res.headers;
return json;
})
.catch((err)=>Observable.empty()) // return empty if error
.share(); // to ensure that no duplicate http calls can occur
}
//in component:
this.service.logout()
.do(()=>this.router.navigate(['LandingPage']);)//do stuff
.subscribe((res:any)=>{});
//or with template async pipe:
public result$ = Observable<T>;
result$ = this.service.logout()
.do(()=>//do stuff);
//in template:
{{(result$ | async)?.id}}
or simply
{{result$ | async}}
// P.s. do not forget about unsubscribe(), thats why I prefer to use async (since that's the Async pipe's job.)
For more information about operators/methods: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/observable.md