-1

I tried using async/await to avoid *ngIf in the component template.

I'm getting an error in the Chrome console when I remove *ngIf in component template.

Can anyone help to get a solution. I do not want to use *ngIf in the component template as a requirement

I'm calling the GET REST API and used subscribe. Also, I'm getting results without the error if I'm using *ngIf, but I want the same results without using *ngIf

CODE: component.ts

export class DisplayComponent implements OnInit {
users : user[];
user: user;
userResult: any;

  constructor(private http: HttpClient) { }

  ngOnInit() {
  }


  async readUser(id){
     this.userResult = await this.http.get<user>("http://localhost:8090/user/" +id).subscribe(
       data => {
         this.user = data;
       },
       error =>{
         return console.error();
         ;
       }
     )
    console.log("Fuuhhh! Client will wait till promise is resolved.");
  }
}

CODE: DisplayComponent.html

<div style="text-align: center;">
    <button (click)="loadUsers()">load Users</button>
    <table style="margin: 0 auto;" border="1">
        <tr>
            <th>Identity</th>
        </tr>
        <tr *ngFor="let user of users">
           <td>
            <button style="background: transparent;border: transparent;cursor: pointer;" (click)="readUser(user.id)">{{user?.id}}</button>
            </td>
        </tr>
    </table>

</div>
<div style="text-align: center;">
    <span style="color: darkgray;">Identity:</span> <span style="color: gray;">{{user.id}}</span> <br>
    <span>Name:</span> {{user.name}} <br> 
    <span>School:</span> {{user.school}} <br> 
</div>

5 Answers5

0

I think you have to use the ngIf because, your template loads before it gets your data. So your HTML is prepared to get the data. What you can do, and its more clean, is to create a boolean var:

isDataReady: Boolean = false;

Then in your html just use it because it will always be false until you change it in your component when the subscription gets the data.

Also, in my projects i use an angular material spinner, to let the user know its loading the back end data with this variable i created.

Hope it helps!

Pau
  • 138
  • 2
  • 14
  • Actually yes are correct that template loads before getting data form the Server. If I am not using *ngIf than I m getting Error "ERROR TypeError: Cannot read property 'id' of undefined at Object.eval [as updateRenderer]" >>>>So I m trying not to use *ngIf and I error can get resolved. *POINT IS I have so many templates, So I cannot waste time just adding *ngIf everywhere. This is the thing. Thanks – Chintan Raval May 30 '20 at 10:49
  • you can just wrap everything that will contain api data in a big div with the conditional and it will be just an ngif – Pau May 30 '20 at 11:19
0

I think you are not using the *ngIf in the right way.All you need to do is add a *ngIf in your template as following, you dont need to add multiple *ngIf for every tags.

<div style="text-align: center;" *ngIf="user">
    <span style="color: darkgray;">Identity:</span> <span style="color: gray;">{{user.id}}</span> <br>
    <span>Name:</span> {{user.name}} <br> 
    <span>School:</span> {{user.school}} <br> 
</div>
Shijil Narayanan
  • 1,011
  • 8
  • 21
  • I know *ngIf will show the users information. But this is just a small block of HTML & I have many blocks many!, So my point for this Question is finding a way to avoid *ngIf and I can show the users information also without using *ngIf! – Chintan Raval May 30 '20 at 10:56
  • There is no harm in using *ngif in your template as and when required, its purpose is to show and hide information only conditionally, and its the cleanest way to hide or show things within template when it comes to Angular – Shijil Narayanan May 30 '20 at 10:58
  • Shijil Narayan Yes you are correct! But If u can help me finding alternative way – Chintan Raval May 30 '20 at 11:06
  • There are many dirty ways to do it, like using css display none on your html and set it to display block within typescript when you get the user object from backend, but i will never recommend you to do that – Shijil Narayanan May 30 '20 at 11:08
0

Angular have a lifecycle system, so Angular is trying to load the component before getting the data from your API. So yes, you need to handle the case before the API responds.

You have 2 ways to do that :

  • use *ngIf but you don't have to use *ngIf everywhere if you make many calls if this is your fear, you can use ngrx properly and use one *ngIf only in your HTML

  • initialize your data with default value. Angular will load your "default" user and replace it by the user received by the API, if there is no error of course. If you really want to use that, try a

user: user = new user();

and of course, initiliaze all the attribute you are using by empty string, ... in the user constructor.

But I think the first way is better because you can handle the error and the waiting case more properly with a loading spinner, loading and error message, ... BUT you need to learn basics of rxjs :)

Gauthier T.
  • 556
  • 1
  • 4
  • 16
0

The code that you have for storing the userResult is not a promise, is a subscription:

async readUser(id){
     // this block is wrong, userResult is a subscription
     this.userResult = await this.http.get<user>("http://localhost:8090/user/" +id).subscribe(
       data => {
         this.user = data;
       },
       error =>{
         return console.error();
         ;
       }
     )
    console.log("Fuuhhh! Client will wait till promise is resolved.");
  }

If you want to use promises (but you should you observables in Angular) you can do it using toPromise() method like this:

async readUser(id){
     try {
       this.userResult = await this.http.get<user>("http://localhost:8090/user/" +id).toPromise();
       this.user = this.userResult // if you really want an extra step here
    } catch(error) {
      console.log(error);
    }
  }

Regarding your question, you should use *ngIf for this case.

For blocks of code use it with ng-container like so:

<ng-container *ngIf="user">
   .....
</ng-container>
ionut-t
  • 1,121
  • 1
  • 7
  • 14
0

Thanks, Folks for trying to help me out in different ways. But yes I didn't get a resolution from the answers.

Finally, I got the solution myself doing some R&D on "avoiding *ngIf", and following is the in-short solution:

Using Angular "Resolver" service I got the data before rendering the template/View.