Peyman Kheiri
Peyman Kheiri

Reputation: 427

How can I access the object property inside subscribe to render the HTML?

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

Answers (7)

Caio Oliveira
Caio Oliveira

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

shahidfoy
shahidfoy

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

Abolfazl Roshanzamir
Abolfazl Roshanzamir

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

Antonis
Antonis

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

igor_c
igor_c

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

yazantahhan
yazantahhan

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

Sajeetharan
Sajeetharan

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

Related Questions