Search code examples
javascriptangularangular-ng-if

Angular 5 show "No data found" on ngIf empty results


I'm using Angular 5 and I'm building a list of items with some buttons that filter the list. What I'm struggling to do is show a "No data found" kind of message when one of those filters hide every item of the list.

It's basically this:

The filter buttons

<div padding>
    <ion-segment [(ngModel)]="filter" (ionChange)="onFilterChange()">
        <ion-segment-button value="all">
            All
        </ion-segment-button>
        <ion-segment-button value="2">
            Pending
        </ion-segment-button>
        <ion-segment-button value="1">
            Confirmed
        </ion-segment-button>
    </ion-segment>
</div>

The list

<ion-list *ngFor="let r of (reservations | async)">
    <ion-card *ngIf="(filter == 'all' || filter == r.confirmed)">
        <ion-item>
            Item
        </ion-item>
    </ion-card>    
</ion-list>

Note: I'm using the async pipe because data comes from Firebase Realtime Database.

So, all my items are in a state of pending (having confirmed: 2), so when I click on the Confirmed button, all the items on the list get hidden, which is perfect. But how can I show a "No data found" message instead of an empty list?

I've tried the else condition, but I'm getting multiple "No data found" messages (one for each hidden item):

<ion-list *ngFor="let r of (reservations | async)">
    <ion-card *ngIf="(filter == 'all' || filter == r.confirmed); else empty;">
        <ion-item>
            Item
        </ion-item>
    </ion-card>    
</ion-list>
<ng-template #empty>
    No data found...
</ng-template>

So what's the correct way of achieving this? Thanks.


Solution

  • IMO you shouldnt display the raw list of reservations. Instead, display the already filtered list:

    component.html

    <ion-segment [formControl]="status" (ionChange)="onFilterChange()">
        <ion-segment-button value="2">
            Pending
        </ion-segment-button>
        <ion-segment-button value="1">
            Confirmed
        </ion-segment-button>
    </ion>
    
    <div *ngIf="empty$ | async; else notEmpty">
       Nothing
    </div>
    <ng-template #notEmpty>
       <ion-list *ngFor="let reservation of reservations$ | async">
            <ion-card>
                <ion-item>
                    Item
                </ion-item>
            </ion-card>    
        </ion-list>
    </ng-template>
    

    component.ts

    import {combineLatest} from 'rxjs/observable/combineLatest';
    import {FormControl} from '@angular/forms';
    
    status= new FormControl;
    reservations$: Observable<IReservation[]>;
    empty$: Observable<boolean>;
    
    constructor(){
       this.reservations$ = combineLatest(rawReservations$,this.status.valueChanges,this._applyFilter);
      this.empty$ = this.reservations$.map(reservations => reservations.length === 0);
    }
    
    private _applyFilter(reservations: IReservation[], status: number): IReservation[]{
      let result = reservations;
      //apply filter logic
      return result;
    }