2

I am trying to show one of the headers according to the value of isComplex$ observable in *ngIf:

<complex-header *ngIf="isComplex$ | async; else ordinaryHeader"></complexheader>
<ng-template #ordinaryHeader>
  <ordinary-header></ordinary-header>
</ng-template>

The problem is *ngIf goes with else case without waiting for observable to emit value. How can I accomplish both of headers wait for observable to emit its first value.

Hikmat G.
  • 2,591
  • 1
  • 20
  • 40
  • 2
    so you want it to display `complex-header` when `isComplex$` is resolved to true, and display `ordinary-header` when `isComplex$` is resolved to false. What do you want to display then, when `isComplex$` is **NOT** resolved yet? – CozyAzure May 30 '18 at 06:31
  • For now it doesn't matter, is it important? I mean I know it's stupid UX, but for now I am just interested if there is a way to do this using asyncpipe? – Hikmat G. May 30 '18 at 07:46
  • 1
    no, it does matter. Cos your case now, it is exactly showing `ordiary-header` when it is **unresolved**. That is because when unresolved, your `ngIf` is treating it as falsy, hence it will be showing `ordinary-header`. So technically it is behaving correctly, unless you specifically said `unresolved` has another specific header. – CozyAzure May 30 '18 at 07:48
  • So I can't use ngIf else here, but two seperate ngIf s and two asyncpipes? Can I do it with only one asyncpipe? – Hikmat G. May 30 '18 at 08:18
  • You are right. That is because `ngIf` is never meant for `async` purposes. There is lots of workaround though. If you insist to use a single async pipe, there is always a lag time before async is resolved and the template rendered. If you do not want to provide another specific header for `unresolved` scenario then its moot. – CozyAzure May 30 '18 at 09:15
  • Of course, that's right, I will put some loading there. Can you give any recommended workaround for this situation? – Hikmat G. May 30 '18 at 09:38

2 Answers2

3

Use angular5 *ngIf else directive.

<div class="course-detail" *ngIf="isComplex$ | async as isComplex else ordinary">
   <complex-header *ngIf="isComplex"></complex-header>
   <ordinary-header *ngIf="!isComplex"></ordinary-header>
</div>
<!-- Showing ordinary header for cases when observable is not returned this can be replaced wuth loader as well-->
<ng-template #ordinary>
    <ordinary-header></ordinary-header>
</ng-template> 

Also see https://blog.angular-university.io/angular-reactive-templates/

Yamini Chhabra
  • 1,119
  • 7
  • 9
2

The solution to not use async pipe multiple times is to wrap everything in a ng-container with the async pipe and use *ngFor. But to use *ngFor isComplex$ must always emit an itterable. So we need a new observable to use in the template:

isComplexIterable$ = isComplex$.pipe(map(isComplex => [isComplex]))

<ng-container *ngFor="let isComplex of isComplexIterable$ | async">
   <complex-header *ngIf="isComplex"></complexheader>
   <ordinary-header *ngIf="!isComplex"></ordinary-header>
</ng-container>
Vega
  • 27,856
  • 27
  • 95
  • 103
  • I've already tried this. It doesn't work if isComplex$ emits `false` which removes entire ng-container from DOM and therefore ordinary-header too. Just emit `false` in your demo, see what happens. – Hikmat G. May 30 '18 at 21:02
  • Now it shows ordinary-header in the beginning without waiting for observable to resolve – Hikmat G. May 30 '18 at 21:13