1

I'm using

Angular 5.2

Firestore

Using *ngIf isContent else noContent, I am trying to render an Observable only if it's populated with data. The logic isn't hitting the else statement. It's rendering isContent even when there's no data. I have poured through these similar stack overflow questions and it looks like my syntax is correct. What am I doing wrong?

Here's the code.

<ng-container *ngIf="months2025 | async as months; else nocontent">

  #### RENDERING REGARDLESS OF MONTHS2025 ####
  <div class="column">
    <h1>2025</h1> #### <-- THIS SHOWS UP ####
    <ul>
      <li *ngFor="let month of months">
        <a href={{month.url}}> {{ month.fileName }} </a>
      </li>
    </ul>
  </div>

</ng-container>

#### NOT RENDERING WHEN NOCONTENT ####
<ng-template #nocontent>
</ng-template>

Here is the component.ts

export class MinutesComponent {
  monthsArray2025: AngularFirestoreCollection<any>;
  months2025: Observable<any[]>;

  constructor(private afs: AngularFirestore) {
    this.monthsArray2025 = afs.collection<any>('minutes', ref => ref.where('year', '==', 2025);
    this.months2025 = this.monthsArray2025.valueChanges();
  }
}
John
  • 521
  • 1
  • 7
  • 23

2 Answers2

2

It looks like you are getting an empty array from your observable i.e. [] which is truthy.

You need to check for length as well.

<ng-container *ngIf="(months2025 | async) as months && months.length>0; else nocontent">

As I mentioned in my comment there is an open issue to allow a construct where such a check is possible in angular.

One workaround is to use a map to force undefined/null when you have empty array.

 this.months2025 = this.monthsArray2025.valueChanges().pipe(map(mnths=>mnths && mnths.length>0?mnths:undefined));

Another is to use two different *ngIf as mentioned by @John here

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • That hits the else statement effectively, but does not display when I populate months2025 with data, e.g. when length > 0 is true. – John Jun 25 '18 at 15:44
  • Sorry was checking length of observable instead of array. Try the update – Suraj Rao Jun 25 '18 at 16:05
  • Hmm. This `*ngIf="months2025 | async as months && months.length>0; ..."` and this *ngIf="(months2025 | async as months && months.length>0); ..."` and this *ngIf="(months2025 | async as months) && months.length>0; ..."` and this *ngIf="((months2025 | async as months) && months.length>0); ..."` all lead to template parse errors in the console: `Unexpected token &&` – John Jun 25 '18 at 16:32
  • If this changed one doesn't work , I will try and post later... I am outside. – Suraj Rao Jun 25 '18 at 16:43
1

So, there is a Github issue about this topic. For now, the simplest workaround I found is a pair of *ngIf containers.

<ng-container *ngIf="months2025 | async as months">
  <ng-container *ngIf="months.length > 0; else nocontent">
    <div class="column">
      <li *ngFor="let month of months">
        <a href={{month.url}}> {{ month.fileName }} </a>
      </li>
    </div>
  </ng-container>
</ng-container>

<ng-template #nocontent>
</ng-template>
John
  • 521
  • 1
  • 7
  • 23