Reputation: 982
I am trying to build a filter using checkboxes. Down below is a snippet of my code:
filter.pipe.ts
import { Pipe, PipeTransform, Injectable } from '@angular/core';
@Pipe({
name: 'filter2'
})
@Injectable()
export class FilterPipe implements PipeTransform {
transform(items: any[], field: string, value: string): any[] {
if (!items) {
return [];
}
if (!field || !value) {
return items;
}
var newArray = [];
items.filter(singleItem => {
if (singleItem != null && singleItem[field] != null && singleItem[field] != undefined && singleItem[field].includes(value)) {
newArray.push(singleItem);
}
})
return newArray;
}
}
app.html
<ng-container *ngFor="let group of groups; let i=index">
<label class="btn btn-filter" id="bttns">
<input type="checkbox" name="customersGroupFilter" autoComplete="off" [value]="group" (change)="changeGroup($event)">
{{ group }}
</label>
</ng-container>
.....
<tr *ngFor="let user of usersList | filter2: 'group' : groupValue">
.....
app.ts
groups = ['a', 'b', c']
usersList = [{'name': 'john', 'group': 'a'}, {'name': 'mike', 'group': 'a'}, {'name': 'doe', 'group': 'b'}, {'name': 'tim', 'group': 'c'}]
groupValue
changeGroup(event) {
this.groupValue = event.target.value
}
This works fine, but if I want to make multiple checks, the new checkbox value will always override my previous value, so multicheck won't be possible.
eg.:
if I check group 'a' => it will return me john, mike
if I check 'a' and 'b' => it will return me only doe
How can I modify my code to achieve what I want? Thank you for your time!
Upvotes: 0
Views: 408
Reputation: 74
Here is a working example if you really want to use Angular Pipe https://stackblitz.com/edit/angular-qw7kkf
You need to change your transform function in Pipe to support multiple group values
transform(items: any[], field: string, value: string[]): any[] {
if (!items) {
return [];
}
if (!field || !value || value.length <= 0) {
return items;
}
return items.filter(singleItem => {
return (singleItem != null && singleItem[field] != null && singleItem[field] != undefined && value.indexOf(singleItem[field]) >= 0);
});
}
See that the type of value changed from string to string[], and also the usage of Array.filter function
2.Change the type of groupValue from string to string[], too. And this is your new changeGroup() function
changeGroup(event) {
const group = event.target.value;
const index = this.groupValue.indexOf(group);
if ( index < 0) {
this.groupValue.push(group);
} else {
this.groupValue.splice(index, 1);
}
const newGroupValue = [];
newGroupValue.push.apply(newGroupValue, this.groupValue);
this.groupValue = newGroupValue;
}
Now to check a group also means trigger it in groupValue. And notice that how cumbersome I have to assign a new array to this.groupValue every time, because if you don't do so, the filter2 Pipe won't detect the change "inside" this.groupValue array. That's also the reason I don't recommend Pipe for your usage scenario, it's a bit over for Angular Pipe.
Upvotes: 1
Reputation: 73241
You are doing some things the wrong way. First, you shouldn't use a filtering pipe. That filter will get called many times per second and will potentially slow down your application. Instead, run the filter function on click of a checkbox.
changeGroup(event) {
// filter function here
}
The second thing that jumps to my eyes is the misuse of filter. Array.filter()
filters the array for you - the if statement must really be the callback's return value
this.newArray = items.filter(singleItem =>
singleItem != null && singleItem[field] != null && singleItem[field] != undefined && singleItem[field].includes(value)
)
You can then use newArray...
So your formerly filtered userList becomes
<tr *ngFor="let user of newArray">
Upvotes: 1