-3

Here is my typescript page.

export class ListUsersComponent implements OnInit {
  users: any;
  constructor(){}

  async ngOnInit() {
    await this.loadUser();
  }

  async loadUser() {
      const us = this.userService.getUsers().pipe(
       first(),
      catchError((errorMessage) => {
        return of(EMPTY_UserProfile);
      })
).subscribe((data: any) => {
  this.users = data;
  console.log(this.users);
});
this.subscriptions.push(us);
  }
}

As the this.user bind easily, it gives me result as

[
  {
    "id": 1,
    "userName": "xyz",
  },
  {
    "id": 2,
    "userName": "xyz2",
  }
]

Here is the HTML ngFor.

<tr align="center" *ngFor="let user of users | async; let i=index">
     <td>{{user.id}}</td>
     <td>{{user.userName}} </td>
</tr>

There is no output shown as I tried every possible way I found through articles. It works when I try to call a fixed Array JSON object in the constructor but calling async await in ngOnInit doesn't really help me. I might be missing something?

Update 1:

Here is the observable part where service is being called.

    getUsers(id?: string): Observable<UserDetails> {
    const auth = this.getAuthFromLocalStorage();
    if (!auth || !auth.authToken) {
      return of(undefined);
    }

    this.isLoadingSubject.next(true);
    return this.userHttpService.getUsers(auth.authToken, '').pipe(
      map((user: UserDetails) => {
        if (user) {
          this.currentUsers = new BehaviorSubject<UserDetails>(user);
        } else {
          this.logout();
        }
        return user;
      }),
      finalize(() => this.isLoadingSubject.next(false))
    );
  }

Update 2: this calls from Update 1 as this.userHttpService.getUsers(auth.authToken, '')

getUsers(token, Id?: string): Observable<UserDetails> {
    const httpHeaders = new HttpHeaders({
      Authorization: `Bearer ${token}`,
    });
    return this.http.get<UserDetails>(`${API_URL}/GetCompanyUsers?Id=` + Id + `&pageNumber=1` + `&pageSize=1`, {
      headers: httpHeaders,
    });
  }
  • @GRD cause I'm calling a HTTP request –  Mar 13 '22 at 09:45
  • There is not any need to async await, you can do http call without it. – GRD Mar 13 '22 at 09:47
  • so getUsers and getUserProfile both are different method ? – GRD Mar 13 '22 at 10:05
  • Observables ≠ Promises. You *do not* need to use [`async/await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) when using observables. Also the [`async`](https://angular.io/api/common/AsyncPipe) you used in the HTML is not the same as the Javascript `async`. Rule of thumb: Subscription to an observable in the TS file and `async` pipe in the HTML file are mutually exclusive. You only need to use one of them on an observable. Not both. – ruth Mar 13 '22 at 10:13
  • @NamanKumar for inner observable you can use mergeMap or concateMap rxjs operator too, this will ease your calling of subscription. – GRD Mar 13 '22 at 10:23

2 Answers2

0

A couple of things here.

  1. No need to add async await here as GRD also said in the comment.
  2. you already subscribing so no need to use the async pipe.

Note: if you are directly using observable then use async pipe.

  users: any[] = [];
  constructor(){}

  ngOnInit() {
    this.loadUser();
  }

  loadUser() {
      const sb = this.userService.getUsers().pipe(
       first(),
       catchError((errorMessage) => {
        return of(EMPTY_UserProfile);
       })
      ).subscribe((users: UserProfile[]) => {
      this.users = users; //data is recieved but not shown on ngFor HTML page
    });
    this.subscriptions.push(sb);
  }
}
<tr align="center" *ngFor="let user of users; let i=index">
     <td>{{user.id}}</td>
     <td>{{user.userName}} </td>
</tr>
harpal
  • 426
  • 4
  • 12
  • there is observable involved in this I'll give an update for this as well on question. –  Mar 13 '22 at 10:01
  • userService.getUserProfile returns observable, that you are already subscribing and assigning the result in users property. Other than that is there any other observable involved? – harpal Mar 13 '22 at 10:06
  • this.userHttpService.getUsers(auth.authToken, '') this also calls Observable which binds in the model I've updated the questions with new update –  Mar 13 '22 at 10:16
  • Sorry wrong update will rectify –  Mar 13 '22 at 10:33
  • Still, there is no other observable involved, you are just returning it from one method(level) to another. and at the end subscribing to your component. – harpal Mar 14 '22 at 07:11
  • I found out that after using menu routing to reach this page the list appears but when I reload the page with F5 it doesn't show, so the answer is correct as above and which I was doing with Array also shows the result with routing but page reload does not help load it. –  Mar 28 '22 at 20:01
  • It depends where you are persisting(if) the menu-item on UI(service instance or local/session storage). Try to refresh menu on every hard reload. But I can't see any menu-related thing in this question, so please ask a new question with details. – harpal Mar 29 '22 at 04:48
0

As the async pipe definition states

The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted.

You'll need to apply async pipe, if you are binding to an observable, in your case in the loadUser() method you are subscribing to an observable and hence no need to use async pipe.

If you want to apply async pipe, then modify the loadUser method like this

  loadUser():Observable<any[]> {
  const sb = this.userService.getUserProfile().pipe(
   first(),
   catchError((errorMessage) => {
    return of(EMPTY_UserProfile);
   })
  );
this.subscriptions.push(sb);
return sb;
 }

and then you'll have to modify the *ngFor like this

<tr align="center" *ngFor="let user of loadUser() | async; let i=index">
 <td>{{user.id}}</td>
 <td>{{user.userName}} </td>
</tr>
Obaid
  • 2,563
  • 17
  • 15
  • 1
    Binding a function to a directive like `*ngFor` with default change detection strategy will trigger the function multiple times (essentially a trigger for each change detection cycle) which could like to performance issues later down the road. – ruth Mar 13 '22 at 10:51
  • yeah agreed, just for a demonstration purpose that async pipe is only applicable on observables (or promises) – Obaid Mar 13 '22 at 14:56