By fana


2018-02-13 13:34:56 8 Comments

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.

2 comments

@Jota.Toledo 2018-02-13 14:06:58

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;
}

@fana 2018-02-13 14:39:25

This seems to be a smart approach. I'll try to convert your code (I'm using Angularfire2 and Firebase) and see if it works.

@Jota.Toledo 2018-02-14 13:26:40

This can indeed by further improved by using some more advanced techniques (presentation component + transclusion); you could drop the empty$ and the ng-if-else. If you are interested in it let me know so I can update the answer.

@SrAxi 2018-02-13 13:58:32

Try this approach and tell me if it works for you.

Component:

// control variable
  dataAvailable = false;

  onFilterChange(filterType: number) {
    // your code and logic

    // This is pretty ugly, make it prettier please...    

    // checking if exists at least 1 reservation with confirmed = 1 | 2 (depends on argument).
    this.dataAvailable = this.reservations.filter(res => res.confirmed === filterType).length > 0;
  }

Template:

<div *ngIf="dataAvailable; then printData else empty"></div>

<ng-template #printData>
  <ion-list *ngFor="let r of (reservations | async)">
      <ion-card>
          <ion-item>
              Item
          </ion-item>
      </ion-card>    
  </ion-list>
</ng-template>
<ng-template #empty>
    No data found...
</ng-template>

So, my idea is that first we check if it's worth to loop through the data in the template. We check this in the component, we see if it exists any reservation with the filtered values.

If it doesn't exist, we won't loop, we just display (no data). If it does exist though, we'll loop and print them...

Does it makes sense? Hope it helps you or at least points you to the right direction!

@fana 2018-02-13 22:11:54

thanks I guess this would work, but decided to go with @Jota.Toledo because a very large list could perform better with his code

@SrAxi 2018-02-14 08:13:29

@fana All good man! I'm glad you found a solution! ;)

Related Questions

Sponsored Content

1 Answered Questions

Angular 2: loading individual data for ngFor items on demand

6 Answered Questions

[SOLVED] How to use *ngIf else in Angular?

0 Answered Questions

dynamically using ion-segment throwing error

0 Answered Questions

Angular 4 how to filter group data in ngFor

  • 2017-12-03 22:29:08
  • Witek85
  • 144 View
  • 0 Score
  • 0 Answer
  • Tags:   angular

2 Answered Questions

[SOLVED] empty button because of a checkbox

1 Answered Questions

[SOLVED] Unable to show different div if data is empty

4 Answered Questions

[SOLVED] Angular : loop over object data loaded from a webservice

2 Answered Questions

[SOLVED] Show/Hide item from list in *ngFor

1 Answered Questions

Angular2 and W3C HTML validation

1 Answered Questions

[SOLVED] In Angular2 how do you detect that a filter/pipes returned no results

  • 2016-11-12 15:21:16
  • AngularM
  • 687 View
  • 1 Score
  • 1 Answer
  • Tags:   angular

Sponsored Content