Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter by pills/buttons instead of using a select - angular

I'm building with Angular and have used a filter pipe to filter on the selected option from my dropdown on the *ngFor loop. The content then filters accordingly. I want to swap the select options to buttons or pills. So when a button is clicked the filter takes place - the button will act as a on/off switch so you can have more than one option filtered.

Here is my stackblitz example - https://stackblitz.com/edit/timeline-angular-7-tyle1f

    <div class="form-group row">
      <div class="col-sm">
        <select class="form-control" name="locationFilter" id="locationFilter" [(ngModel)]="filteredLocation">
          <option value="All">All</option>
          <option *ngFor="let entry of timeLine | filterUnique" value="{{entry.location}}">{{entry.location}}
          </option>
        </select>
      </div>
//Button filters below
       <div ngDefaultControl [(ngModel)]="filteredLocation" name="locationFilter" id="locationFilter">
            <button class="btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique">{{entry.location}}</button>
       </div>
    </div>

I'm not sure how to get the buttons to work the same way as no filtering takes place.... any help appreciated!?

like image 610
Tom Rudge Avatar asked Sep 26 '19 08:09

Tom Rudge


Video Answer


4 Answers

Bind a click event (click)="filteredLocation = entry.location" to the button

Try like this:

 <div ngDefaultControl [(ngModel)]="filteredLocation" name="locationFilter" id="locationFilter">
     <button  (click)="filteredLocation = entry.location" class="btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique">{{entry.location}}</button>
  </div>

Working Demo

like image 129
Adrita Sharma Avatar answered Sep 25 '22 02:09

Adrita Sharma


The crux of this is just assign the value of the button/switch to your filteredLocation variable like below

<button (click)="filteredLocation = entry.location" class="btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique">{{entry.location}}</button>

Updated Demo

Hope this helps :)

like image 38
Manish Avatar answered Sep 21 '22 02:09

Manish


Easier to just have a click handler:

<div>
  <button class="btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique" (click)="filter(entry)">{{entry.location}}</button>
</div>

filter(entry) {
  this.filteredLocation = entry.location;
}

Demo: https://stackblitz.com/edit/timeline-angular-7-z2e6zh?file=src/app/timeline/timeline.component.ts

like image 29
Chrillewoodz Avatar answered Sep 23 '22 02:09

Chrillewoodz


If you want to filter on multiple options your filter pipe will have to be adjusted to accomadate an array of strings to filter on.

So in your FilterPipe the transform function gets changed as follows:

transform(value: string[], filterStrings: string[], propName: string): any {
    if (value.length === 0 || !filterStrings || filterStrings.length === 0) {
      return undefined;
    }

    const resultArray = [];
    for (const item of value) {
      if (filterStrings.indexOf(item[propName]) >= 0) {
        resultArray.push(item)
      }
    }

    return resultArray;
}

After that you need to add some code to the timeline.component.ts file:

An array to hold all the active filter options:

filteredLocations: string[] = [];

A function to toggle an option on or off:

toggle(location) {
    let indexLocation = this.filteredLocations.indexOf(location);
    if (indexLocation >= 0) {
      this.filteredLocations = this.filteredLocations.filter((i) => i !== location);
    } else {
      this.filteredLocations.push(location);
    }
}

Now change the template (timeline.component.html):

Remove the selection box.

Add a click handler to your button:

<button (click)="toggle(entry.location)" class="btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique">{{entry.location}}</button>

Lastly, the filter should accept the new filtered locations: (I just changed filteredLocation to filteredLocations)

*ngFor="let entry of timeLine | filter:filteredLocations:'location'"
like image 21
Giovani Vercauteren Avatar answered Sep 21 '22 02:09

Giovani Vercauteren