Reputation: 427
I need to use the properties that I get inside .subscribe
to update the HTML. I know that .subscribe
is asynchronous so the value is undefined before it is resolved, but how can I make it wait until it has the value? At the moment I only get undefined
for the object properties.
This is my service method where I call the API to fetch the data:
fetchCustomers(name: string) Observable<Customer[]> {
return this.http.get<Customer>('MY URL')
}
and the component where I subscribe to it:
customer: any;
name: string;
ngOnInit() {
//this.name = /*code to retrieve the name*/
this.renderCustomer(this.name)
}
renderCustomer(name) {
this.testService.fetchCustomer(name).subscribe(data => {
this.customer = data
})
}
But when I call the method this.customer
remains undefined. I need the properties of data
to render my HTML file like this:
<tr> {{ customer.companyName }} </tr>
<tr> {{ customer.fullName }} </tr>
<tr> {{ customer.Email }} </tr>
How can I make this line this.customer = data
to wait until the Observable
is resolved? I have also tried this.customer = JSON.parse(JSON.stringify(data))
as it was suggested in another thread, but it did not work.
Upvotes: 1
Views: 3101
Reputation: 804
If your problem is only on the HTML itself, you can add a question mark to check if the object is defined first :
<tr> {{ customer?.companyName }} </tr>
Or you could simply use
*ngIf="customer"
```` on the parent div.
If you want to do other things inside your component you can open the callback to do more stuff.
your_component.ts
renderCustomer(name) {
this.testService.fetchCustomer(name).subscribe(data => {
this.customer = data;
foo(data);
})
Upvotes: 1
Reputation: 2301
If customer & name are both coming from subscriptions you might be able to chain them together using rxjs flatMap https://rxjs-dev.firebaseapp.com/api/operators/flatMap
customer: any;
name: string;
ngOnInit() {
this.renderCustomer();
}
renderCustomer() {
this.testService.fetchName(/*variable to retrieve the name*/)
.pipe(
flatMap((name: string) => {
this.name = name;
return this.testService.fetchCustomer(name);
})
).subscribe(data => {
this.customer = data;
});
}
Upvotes: 1
Reputation: 14792
If the customer model is an interface you can set default value null for each property like the following
public customer:Customer={ companyName: null, fullName: null, Email:null }
Then in your html :
<tr> {{ customer.companyName }} </tr>
<tr> {{ customer.fullName }} </tr>
<tr> {{ customer.Email }} </tr>
Another way is to use ?
operator as below :
<tr> {{ customer?.companyName }} </tr>
<tr> {{ customer?.fullName }} </tr>
<tr> {{ customer?.Email }} </tr>
Upvotes: 1
Reputation: 557
You can also use the async
pipe
component
customer$: Observable<any>;
name: string;
ngOnInit() {
this.renderCustomer(this.name)
}
renderCustomer(name) {
this.customer = this.testService.fetchCustomer(name)
})
template
<tr> {{ customer.companyName | async }} </tr>
<tr> {{ customer.fullName | async }} </tr>
<tr> {{ customer.Email | async }} </tr>
Upvotes: 1
Reputation: 1250
You can do what @Sajeetharan suggests or wrap your tr
's into if
:
<ng-container *ngIf="customer">
<tr> {{ customer.companyName }} </tr>
<tr> {{ customer.fullName }} </tr>
<tr> {{ customer.Email }} </tr>
</ng-container>
This way it will be shown only if the customer
has some value
Upvotes: 1
Reputation: 3110
You can use the safe navigation operator in the HTML:
<tr> {{ customer?.companyName }} </tr>
<tr> {{ customer?.fullName }} </tr>
<tr> {{ customer?.Email }} </tr>
You can also display a loader until the data comes. Something like:
<ng-container ngIf="!customer">
<spinner></spinner>
</ng-container>
<ng-container ngIf="customer">
...
<tr> {{ customer.companyName }} </tr>
<tr> {{ customer.fullName }} </tr>
<tr> {{ customer.Email }} </tr>
...
</ng-container>
Upvotes: 1
Reputation: 222522
Your code looks right! Can you try using a safe navigation operator,
<tr> {{ customer?.companyName }} </tr>
<tr> {{ customer?.fullName }} </tr>
<tr> {{ customer?.Email }} </tr>
Upvotes: 6