I've been learning TypeScript with Angular. And currently I stuck as this moment. Previously I used subscribed method and everything works flawlessly, but not I decided to rewrite the code using async pipe and it just does't work....
- RestAPI retursn requests in particular format
export interface responseFormat {
success: boolean;
data: any;
}
- returned data can be in different types. In this particular case data returns restaurant object... It also might be arrays of different objects...
export interface restaurant {
_id: string;
name: string;
description: string;
images: file[];
cuisines: cuisine[];
blocked: boolean;
created: Date;
business_hours: object;
}
- Previously I used the following code (it works):
/* Provider */
getRestaurant(): Observable<responseFormat> {
return this.http.get<responseFormat>(environment.api + "/restaurant");
}
/* Component */
private restaurant: restaurant;
getRestaurant() {
this.restaurantProvider.getRestaurant().subscribe(res => {
if (res.success) this.restaurant = res.data;
});
}
as a result the type of the variable is assigned.... But I don't want to keep the record of subscriptions thus I wanted to convert the code using Angular async pipe... This is what I've done... it doesn't works
/* Provider */
getRestaurant(): Observable<responseFormat> {
return this.http.get<responseFormat>(environment.api + "/restaurant");
}
/* Component */
private restaurantObservable: Observable<restaurant>;
getRestaurant() {
this.restaurantObservable = this.restaurantProvider.getRestaurant().map(res => <restaurant>res.data);
// or //
this.restaurantObservable = this.restaurantProvider.getRestaurant().map(res => res.data as restaurant);
}
But the above code doesn't cast the type of the response to the interface...
What am I doing wrong???
In other words I can get the Observable variables in template (with https://angular.io/api/common/AsyncPipe> like that:
/* Provider */
getRestaurant(): Observable<responseFormat> {
return this.http.get<responseFormat>(environment.api + "/restaurant");
}
/* Component */
private restaurantObservable: Observable<restaurant>;
getRestaurant() {
this.restaurantObservable = this.restaurantProvider.getRestaurant().map(res => res.data as restaurant);
}
/* Template */
<div class="name">{{ (restaurantObservable | async)?.name }}</div>
// or //
<div *ngIf="restaurantObservable | async as restaurant">
<div>{{ restaurant.name }}</div>
</div>
But I can't get the property of the restaurant observable in component... For instance this.restaurant.cuisines throw the error "property cuisines does not exist on type Observable"
Why not directly return an
Observable<restaurant>
from your service?Then on component side:
The error handling (
success
flag, HTTP errors, etc) could be handled via an HTTP Interceptor.The Angular async template pipe subscribes to the Observable, that is how it is able to access the restaurant object and its properties in the template.
If you want to access to these same thing in the component controller then you need to make a subscription in the component controller.
Given that your rest service or provider returns a Restaurant in this format (i've always used classes not interfaces, sorry i can't provide any help with this distinction, so in my example Restaurant is a class).
You should be able to have angular serialise the response for you as an example:
That is given you also have a also imported the other types Branch, Menu, File, Cuisine into the typescript file containing the restaurant. for example branch would look like