Angular Material - 通过多个过滤器和多个过滤器值同时过滤表
Posted
技术标签:
【中文标题】Angular Material - 通过多个过滤器和多个过滤器值同时过滤表【英文标题】:Angular Material - Filter Table by multiple filters and multiple filter values at the same time 【发布时间】:2019-06-19 21:52:00 【问题描述】:我试图为一个对象表设置两个不同的过滤器。第一个是基于普通文本/输入的过滤器,按预期工作。
我要工作的第二个是一排标记为“1 级”、“2 级”等的复选框。在选中一个复选框时,我想按“级别”列过滤所有当前选中的复选框复选框。理想情况下,用户可以通过文本和级别选择来过滤表格
我已阅读有关使用 filterPredicate 并尝试使用 this as a template 但我一定遗漏了一些东西。
当前代码sn-p:
html:
//Input for text filter
<mat-form-field >
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter...">
</mat-form-field>
...
//Checkboxes for level filter
<div fxLayout="row" fxLayoutAlign="space-between center" class="margin-1">
<mat-checkbox (change)="customFilterPredicate()" [(ngModel)]="level.active" *ngFor="let level of levelsToShow">level.level</mat-checkbox>
</div>
TS
ngOnInit()
this.dataSource.filterPredicate = this.customFilterPredicate();
...
applyFilter(filterValue: string)
this.dataSource.filter = filterValue.trim().toLowerCase();
customFilterPredicate()
const myFilterPredicate = (data): boolean =>
return this.levelsToShow.some(data['level'].toString().trim());
;
return myFilterPredicate;
更新
到目前为止,多亏了 F*** Küng,我才能取得一些进展,但我仍然没有回家。为了澄清,我希望文本过滤器能够搜索多个列(“castingTime”、“duration”等),并且复选框只能按级别过滤。
截至目前,当我点击一个复选框时,我收到此错误: '无法读取未定义的属性'toLowerCase'' 指向这行代码:
return data['level'].toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&
但是当我控制台注销数据时,我可以看到它具有 level 属性,所以我看不到哪里出错了。
以下是相关代码sn-ps:
HTML:
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter..." [formControl]="textFilter">
<mat-checkbox (change)="updateFilter()" [(ngModel)]="level.active" *ngFor="let level of levelsToShow">level.name</mat-checkbox>
TS:
levelsToShow: Level[] = [
level: '1', active: false, name: 'Level 1' ,
level: '2', active: false, name: 'Level 2' ,
level: '3', active: false, name: 'Level 3' ,
level: '4', active: false, name: 'Level 4' ,
level: '5', active: false, name: 'Level 5' ,
level: '6', active: false, name: 'Level 6' ,
level: '7', active: false, name: 'Level 7' ,
level: '8', active: false, name: 'Level 8' ,
level: '9', active: false, name: 'Level 9'
];
levelFilter = new FormControl();
textFilter = new FormControl();
globalFilter = '';
filteredValues =
level: '',
text: '',
;
ngOnInit()
...
this.textFilter.valueChanges.subscribe((textFilterValue) =>
this.filteredValues['text'] = textFilterValue;
this.dataSource.filter = JSON.stringify(this.filteredValues);
);
this.dataSource.filterPredicate = this.customFilterPredicate();
customFilterPredicate()
const myFilterPredicate = (data: Spell, filter: string): boolean =>
var globalMatch = !this.globalFilter;
if (this.globalFilter)
// search all text fields
globalMatch = data['spellName'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['level'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['castingTime'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['distance'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['details'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['duration'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['school'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['effect'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1;
if (!globalMatch)
return;
let searchString = JSON.parse(filter);
return data['level'].toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&
(this.levelsToShow.filter(level => !level.active).length === this.levelsToShow.length ||
this.levelsToShow.filter(level => level.active).some(level => level.level === data.level.toString()));
return myFilterPredicate;
updateFilter()
this.dataSource.filter = JSON.stringify(this.filteredValues);
更新二
这里的要求是其中一个表格行的示例:(这是一个 d&d 法术表)
castingTime: "1 half action"
distance: "Short range attack"
duration: "1 round per Casting Level"
effect: "Once per round, you may take a half action to launch an arrow of acid from your palm, generating a new Spellcasting result to see if you hit.Each arrow inflicts 1d6 acid damage.↵ "
index: 0
level: "4"
school: "Creation"
spellName: "ACID ARROW"
最终更新
这是我最终的结果,以防有人被卡住。感谢 F*** Küng 解决了这一切!唯一需要注意的是我最终使用了文本输入“textFilter”的实际值,因为将文本过滤值字符串化然后解析它们(据我所知,过滤器只接受字符串)不断给我“JSON错误,意外值 0" 消息,据我所知,这将正常工作,除了现在我需要弄清楚如何限制过滤器。
customFilterPredicate()
const myFilterPredicate = (data: Spell, filter: string): boolean =>
var globalMatch = !this.globalFilter;
if (this.globalFilter)
// search all text fields
globalMatch = data['spellName'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['level'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['castingTime'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['distance'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['details'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['duration'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['school'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data['effect'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1;
if (!globalMatch)
return;
return data.spellName.toString().trim().toLowerCase().indexOf(this.textFilter.value) !== -1 &&
(this.levelsToShow.filter(level => !level.active).length === this.levelsToShow.length ||
this.levelsToShow.filter(level => level.active).some(level => level.level === data.level.toString()));
return myFilterPredicate;
【问题讨论】:
你能显示你试图显示/过滤的数据吗?例如。属性和实际的数据行。 是的,我现在就添加它。谢谢! 这一行data['level'].toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&
应该改为使用 searchString.text
而不是 name
,因为您实际上从未设置过 filteredValues
的 name
属性(除非缺少该代码)。
【参考方案1】:
您在设置复选框然后使用复选框模型在customFilterPredicate
函数中进行过滤时处于正确的轨道上。
我使用了链接的 stackblitz 并对其进行了修改以使其适用于您的 复选框,检查它 here.
在模板中,您可以设置复选框:
<mat-checkbox (change)="updateFilter()" [(ngModel)]="level.active" *ngFor="let level of levelsToShow">level.name</mat-checkbox>
在组件中我添加了Level
接口:
export interface Level
active: boolean;
name: string;
level: number;
还有一些数据:
levelsToShow: Level[] = [
level: 1, active: false, name: 'Level 1' ,
level: 2, active: false, name: 'Level 2' ,
level: 3, active: false, name: 'Level 3' ,
];
最重要的部分是customFilterPredicate
函数。它的作用是,它在第一个条件中过滤name
属性,在第二个条件中它检查是否所有级别都设置为false
,在这种情况下,我们返回true
,因为我假设您想查看所有级别如果没有选中复选框。如果一个级别处于活动状态,我们会按该级别进行过滤,如果选择了多个级别,我们会按多个级别进行过滤。
return data.name.toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&
(this.levelsToShow.filter(level => !level.active).length === this.levelsToShow.length ||
this.levelsToShow.filter(level => level.active).some(level => level.level === data.level));
一个小而重要的部分是在您选中/取消选中复选框时实际触发过滤。这可以通过再次设置数据源filter
来完成,并在复选框值更改时调用:
updateFilter()
this.dataSource.filter = JSON.stringify(this.filteredValues);
【讨论】:
非常感谢您的帮助。所以我想我几乎拥有它。为了澄清我希望让文本过滤器过滤多个列。当我尝试使用您发布的闪电战作为指南时,但在“返回数据['level'].toString().trim( ).toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&" 我将使用相关代码更新我的问题。【参考方案2】:如果您使用@angular/material
,您可以使用mat-table-filter 来满足您复杂的过滤要求。
检查这个answer
【讨论】:
【参考方案3】:更简单的方法
在数据源中使用FilterPredicate设置多个表达式
使用表单组分配将发送 filterValue 的控件
<form [formGroup]="filterForm">
<mat-form-field>
<input matInput placeholder="Model" formControlName="model" />
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Type" formControlName="modelType" />
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Status</mat-label>
<mat-select formControlName="status">
<mat-option value=""></mat-option>
<mat-option value="Active">Active</mat-option>
<mat-option value="InActive">InActive</mat-option>
</mat-select>
</mat-form-field>
#TypeScript 指定 filterPredicate 表达式
// Filter Predicate Expression to perform Multiple KeyWord Search
this.dataSource.filterPredicate = ((data: DeviceInventory, filter) =>
const a = !filter.model || data.modelCode.trim().toLowerCase().includes(filter.model);
const b = !filter.modelType || data.modelType.trim().toLowerCase().includes(filter.modelType);
return a && b;
) as (DeviceInventory, string) => boolean;
订阅 FomrGroup 值更改以收听 filterValues
this.filterForm.valueChanges.subscribe(value =>
this.dataSource.filter = value;
console.log(value);
);
【讨论】:
以上是关于Angular Material - 通过多个过滤器和多个过滤器值同时过滤表的主要内容,如果未能解决你的问题,请参考以下文章
在角度 5 中过滤 Angular Material 表中的特定列 [重复]
填充数组并使其可使用 Angular Material 过滤
Angular Material Datepicker:如何过滤以便只允许数组中的日期?
如何过滤mat-tree组件Angular Material 6.0.1