Cody
Cody

Reputation: 61

How to create a custom pipe for filtering with multiple checkboxes? Angular 4

I have a list of statuses whose values are: Dispatched, open, and closed. When I click on a checkbox I want to filter the results

<ion-item *ngFor="let s of appointmentStatus" >
  <ion-checkbox [(ngModel)]="s.checked" (click)="updateFilter(s)"></ion-checkbox>
  <ion-label >{{ s.status }}</ion-label>
</ion-item>

<div *ngFor="let a of todaysAppointments>
//list of appointments goes here

I have tried to come up with a way to do this with pipes, but I have not found a good example and I am rather new. Any help would be appreciated.

if ((appDate.getDay() == currentDate.getDay()) && (appDate.getMonth() == currentDate.getMonth()) && (appDate.getFullYear() == currentDate.getFullYear()) && this.appointments[i].status != 'Pending') {
                this.todaysAppointments.push(this.appointments[i]);
            }
            if ((appDate.getDay() < currentDate.getDay()) && (appDate.getMonth() >= currentDate.getMonth()) && (appDate.getFullYear() >= currentDate.getFullYear()) && this.appointments[i].status != 'Pending') {
                this.upcomingAppointments.push(this.appointments[i]);
            }

So what you did below works perfect when you only have a single array. On my html I have it divided up into Todays and upcoming appointments. So I first have the page load and show all the appointments in there corresponding sections. Then on top of that I want to filter by the checkboxes.

<h2 style="background-color:#387ef5">Today's Appointments</h2>
<div *ngFor="let a of todaysAppointments | filter: searchTerm" (click)="openPage(a)">

<h2 style="background-color:#387ef5">Upcoming Appointments</h2>
<div *ngFor="let a of upcomingAppointments | filter: searchTerm" (click)="openPage(a)">

Upvotes: 2

Views: 2518

Answers (1)

AVJT82
AVJT82

Reputation: 73357

EDIT:

Since we are dealing with two arrays, here is the original answer transformed to a pipe instead of just having the filter method in the component file.

We can also keep the updateFilter(s) method if you want to there add or remove filter values, or you can do it in template for the click event:

(click)="s.checked ? 
    filterArr.push(s.status) : filterArr.splice(filterArr.indexOf(s.status), 1)

I personally like having that logic in the component to keep the template clean, but that is totally up to you :)

And in the template we pass that array to the pipe:

<div *ngFor="let a of todaysAppointments | filterPipe: filterArr">

The pipe would look like this, where values is the array you want to filter, and args is the array with the checkboxes checked. (You'd want to reconsider the naming). We have to make the pipe impure so that it will be fired whenever changes happen.

@Pipe({name: 'filterPipe', pure: false})
export class MyPipe implements PipeTransform {
    transform(values: any, args?: any[]): any[] {
      return values = values.filter(a => {
        return args.length ? args.indexOf(a.status) != -1 : values;
      })      
    }
}

That should do it!

DEMO


ORIGINAL ANSWER:

Maybe a custom pipe is not necessary here at all. You can just use the Array.prototype.filter() on your click event.

Also we need to check if the checkbox is checked or not, and filter based on the values that are checked. I have here inserted them in a separate array, filterArr.

So in updateFilter(s) method we do that check first, push that filter value to the array, or remove it. Then filter by the values, or return all appointments if filterArr is empty:

We have a separate array that stores all appointments called allAppointments, from which we filter the values to todasyAppointments.

updateFilter(appt) {
  if(appt.checked) {
    // checkbox is checked, push to filterArr
    this.filterArr.push(appt.status)
  }
  else {
    // unchecked box, let's remove it from array
    let index = this.filterArr.indexOf(appt.status)
    this.filterArr.splice(index, 1)
  }
  // filter by the values set in filterArr, or if empty, return all appointments
  this.todaysAppointments = this.allAppointments.filter(a => {
    return this.filterArr.length ? 
           this.filterArr.indexOf(a.status) != -1 : this.allAppointments;
  })
}

DEMO

Upvotes: 3

Related Questions