I have 2 filters on a user list. A user can select a group containing members and use the search filter to search by last name. When the user backspaces a user to look for another, this resets the groups to all users. I need this to only show the users in the selected group.
TS
updateFilter(event) {
const val = event.target.value.toLowerCase();
const temp = this.temp.filter(function (d) {
return d.lastName.toLowerCase().indexOf(val) !== -1 || !val;
});
this.rows = temp;
if (this.table) {
this.table.offset = 0;
}
}
onGroupSelected($event) {
const groupId = $event.target ? $event.target.value : $event;
if (groupId === 'none') {
this.rows = this.temp;
} else {
const groupUsers = this.groupUserMap.get(groupId);
if (groupUsers) {
this.rows = this.temp.filter((serviceUser) =>
groupUsers.includes(serviceUser.id));
} else {
this.rows = [];
}
}
// @ts-ignore
this.userSelections = this.userSelections ? this.userSelections : {};
this.userSelections.groupId = groupId;
localForage.setItem(this.username, this.userSelections);
}
HTML
<input
type='text'
class="form-control w-200px"
placeholder='Search by Last Name...'
(keyup)='updateFilter($event)'
/>
<select class="form-control w-200px" (change)="onGroupSelected($event)">
<option value="none">All service users</option>
<option *ngFor="let group of groups"
[value]="group.id"
[selected]="userSelections.groupId === group.id">
{{group.name}}
</option>
</select>
CodePudding user response:
You can use ngModel
with tow-way binding, to save and manipulate search filters:
<select
class="form-control w-200px"
[(ngModel)]="selectedGroup"
(change)="onGroupSelected()"
>
<option value="none">All service users</option>
<option *ngFor="let group of groups" [value]="group.id">
{{ group.name }}
</option>
</select>
<input
type="text"
class="form-control w-200px"
placeholder="Search by Last Name..."
[(ngModel)]="search"
(keyup)="updateFilter()"
/>
And in order not to lose your users table you can create a copy which will be filtered and displayed.
public initialUsers = [
{ id: 100, groupId: 1, name: 'foo' },
{ id: 101, groupId: 2, name: 'bar' },
{ id: 102, groupId: 1, name: 'john' },
{ id: 103, groupId: 2, name: 'doe' },
{ id: 104, groupId: 2, name: 'baaar' },
{ id: 105, groupId: 1, name: 'fooodoe' },
];
public filteredUsers = [];
ngOnInit(): void {
this.filteredUsers = this.initialUsers;
}
Here is a demo on stackblitz, I used a list to go fast but It's just display. You just have to replace <ul> <li></li> </ul>
by your <table> ... </table>
CodePudding user response:
If you would want to take an observable way of doing this, then I would suggest to make a form of your controls, ooooor just use 2 form controls instead. I chose form here as it wraps it up nicely with both form controls (search and dropdown):
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
search: [''],
group: [0] // "all" option as initial id
})
}
Then we would listen to when the form value changes and assign the filtered data to a variable, here named filteredUsers$
.
this.filteredUsers$ = this.form.valueChanges.pipe(
startWith(this.form.value), // to trigger initially
// 'this.users' refers to your original users array
map((value: any) => {
// 'all' option is chosen, just filter based on search
if (value.group === 0) return this.users.filter(x => x.lastName.toLowerCase().includes(value.search))
// filter by group and search
return this.users.filter(x => {
return (x.groupId === value.group) && (x.lastName.toLowerCase().includes(value.search.toLowerCase()))
})
})
)
That is it, then we just iterate filteredUsers$
in the template:
<tr *ngFor="let user of filteredUsers$ | async">
Of course we need the form in the view and it would look like this:
<form [formGroup]="form">
<input
type="text"
placeholder="Search by Last Name..."
formControlName="search"
/>
<select formControlName="group">
<option *ngFor="let group of groups" [ngValue]="group.id">
{{ group.name }}
</option>
</select>
</form>
Here is a DEMO with the above code