angular search filter with boolean checkboxes

1k Views Asked by At

I'm new in Angular, I have a list of components that I want to filter according to some check boxes, using pipes and I don't know how to achieve this.

So far I have an interface

export interface Parking {
    multiple: boolean;
    public: boolean;
    name: string;
}

the pipe

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filter'
})
export class FilterPipe implements PipeTransform {

  transform(value: unknown, ...args: unknown[]): unknown {
    
    return null;
 
  }

}

Search component

<form>
  
    <div class="form-group mt-2">
         <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox">
          <label class="form-check-label" for="inlineCheckbox1" >Public</label>
        </div>
        <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox">
          <label class="form-check-label" for="inlineCheckbox2" >Private</label>
        </div>
    
         <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox">
          <label class="form-check-label" for="inlineCheckbox1" >Single</label>
        </div>
        
        <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox">
          <label class="form-check-label" for="inlineCheckbox1" >Multiple</label>
        </div>
        
    </div>
</form>

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-filter',
  templateUrl: './filter.component.html',
  styleUrls: ['./filter.component.css']
})

export class FilterComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

and in the template for displaying components (map.component.html)

<div *ngFor="let parking of (parkings | filter)">
{{parking.name}}
</div>

I don't know how to continue for filtering according to checkboxes when checked

Thank you!

1

There are 1 best solutions below

4
Daniel Guzman On

Let's create an object that contains all your filter options and initialize them as false.

export class FilterComponent implements OnInit {
  
  public filters = {
    public: false,
    private: false,
    single: false,
    multiple: false,
  }

  constructor() { }

  ngOnInit(): void {
  }

}

Now bind them in your template like this

<form>
  
    <div class="form-group mt-2">
         <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox" [(ngModel)]="filter.public">
          <label class="form-check-label" for="inlineCheckbox1" >Public</label>
        </div>
        <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox" [(ngModel)]="filter.private">
          <label class="form-check-label" for="inlineCheckbox2" >Private</label>
        </div>
    
         <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox" [(ngModel)]="filter.single">
          <label class="form-check-label" for="inlineCheckbox1" >Single</label>
        </div>
        
        <div class="form-check form-check-inline">
          <input class="form-check-input" type="checkbox" [(ngModel)]="filter.multiple">
          <label class="form-check-label" for="inlineCheckbox1" >Multiple</label>
        </div>
        
    </div>
</form>

So whenever any of these is checked it's value will be true. Now, pass this filters object to your pipe: parkings | filter : filters

<div *ngFor="let parking of (parkings | filter : filters)">
  {{parking.name}}
</div>

and get them in your filter

transform(values: Parking[], filters:any): Parking[]{
  
  // In case this is not getting any filters object, just return the same array
  if(!filters)
    return values;


  /*** If actually got filters, just use the filter() method that arrays have ***/

  // If you checked the "public" checkbox this if() statement will be solved to true
  // so executates this filtering
  if(filters.public){
    // This is gonna filter array and return only current items where public is true
    values = values.filter(item => item.public); // item => item.public == true
  }

  if(filters.multiple){
    // This is gonna filter the filtered array again, so if you already
    // excluded the private ones (so if parking.public is false),
    // now based on that results you will keep 
    values = values.filter(item => item.multiple);
  }

  return values;

}

This way you can continue filtering. I'm executing each filter manually in case you'd like to add different conditions and so, but let's imagine you have a list of 10 filters where the condition will be always the same: values = values.filter(item => item.something == true); you could simplify this by looping the filters object with Object.keys() wich returns an array of keys from the object. Just like this:

transform(values: Parking[], filters:any): Parking[]{
  
  if(!filters)
    return values;

  Object.keys(filters).forEach(key => {
    if(filters[key]){
      values = values.filter(item => item[key]);
    }
  })

  return values;

}

Note: this last method applies if your Parking properties are the same that the filters ones.