动格过滤管
Dynamic grid filter pipe
我有一个如下所示的通用网格
<table class="table">
<thead>
<tr role="row" class="headers-filters">
<th *ngFor="let objGColumn of gridColumns; let idx=index;">
<dt-column-header [(filter)]="grdFilters[objGColumn.propertyKey]"></dt-column-header>
</th>
</tr>
</thead>
<tbody>
<tr role="row" *ngFor="let objRC of recordList | filterColumn: grdFilters; let idx=index;">
<td class="text-center" *ngFor="let objGColumn of gridColumns; let idx=index;">
<span [textContent]="objRC[objGColumn.propertyKey]"></span>
</td>
</tr>
</tbody>
</table>
其中 gridColumns 将是显示列的数组。
dt-column-header 是一个包含搜索列文本框的组件。它有双向绑定 属性 过滤器,这将是网格中的过滤器
过滤器会像 grdFilters = {LastName: "123", FirstName: "456"}
我的烟斗是这样的。我参考了 https://www.code-sample.com/2018/07/angular-6-search-filter-pipe-table-by.html
@Pipe({
name: 'filterColumn'
})
export class GrdFilterPipe implements PipeTransform {
transform(items: any, filter: any, defaultFilter: boolean): any {
if (!filter){
return items;
}
if (!Array.isArray(items)){
return items;
}
if (filter && Array.isArray(items)) {
let filterKeys = Object.keys(filter);
if (defaultFilter) {
return items.filter(item =>
filterKeys.reduce((x, keyName) =>
(x && new RegExp(filter[keyName], 'gi').test(item[keyName])) || filter[keyName] == "", true));
}
else {
return items.filter(item => {
return filterKeys.some((keyName) => {
return new RegExp(filter[keyName], 'gi').test(item[keyName]) || filter[keyName] == "";
});
});
}
}
}
}
我的第一个问题是当 gridFilters 改变时管道没有调用。我不得不让它变得 不纯 这会影响性能。
另一个问题是管道在 {LastName: "123"}
或 {FirstName: "456"}
下工作正常
但是无法使用 {LastName: "123", FirstName: "456"}
OR {LastName: "", FirstName: "456"}
OR {LastName: "123", FirstName: ""}
快速回答:
"My first issue is pipe is not calling when gridFilters change":
推荐: 将管道保留为纯管道并重新分配 gridFilters
而不是修改它。换句话说,不要在 dt-column-header
组件中使用 ngModel,而是使用输入事件并重新分配 gridFilters
变量。
或(不推荐): 通过在 @Pipe
装饰师:
@Pipe({
name: 'searchFilter',
pure: false
})
请参阅此 StackBlitz DEMO 以及可用的示例代码。
"Another issue is pipe works fine with... But not working with":
问题出在管道的代码上:
return items.filter(item => {
return filterKeys.some((keyName) => {
return new RegExp(filter[keyName], 'gi').test(item[keyName]) || filter[keyName] == "";
});
});
显然您没有得到想要的结果。你没有提到你想要得到的结果的问题,你是什么意思 working/not working?根据您的需要编辑您的问题,我会更新我的答案。
详细解答
解释 pure/impure 管道:
您的管道是纯管道(在@Pipe 装饰器中不使用元数据pure: false
时的默认管道类型)。只有当原始输入值(字符串、数字、布尔值、符号)发生变化或对象引用(日期、数组、函数、对象)发生变化时,纯管道才会执行。
因此,您有 2 个选项作为解决方案:
方案一(推荐):
为了让您的管道在 gridFilters 更改时再次调用,您需要重新分配它而不是修改它。换句话说,不要在 dt-column-header
组件中使用 ngModel,而是使用输入事件并重新分配 gridFilters
变量。
方案二(不推荐):
通过在 @Pipe
装饰器中添加 pure: false
使您的管道成为 不纯管道 :
@Pipe({
name: 'searchFilter',
pure: false
})
这一次,您的管道将在每个组件更改检测周期中执行。
这也是不推荐此解决方案的原因,因为它会经常被调用,就像每次击键或鼠标移动一样频繁。
Angular Docs - Impure pipes 说:
With that concern in mind, implement an impure pipe with great care. An expensive, long-running pipe could destroy the user experience.
我有一个如下所示的通用网格
<table class="table">
<thead>
<tr role="row" class="headers-filters">
<th *ngFor="let objGColumn of gridColumns; let idx=index;">
<dt-column-header [(filter)]="grdFilters[objGColumn.propertyKey]"></dt-column-header>
</th>
</tr>
</thead>
<tbody>
<tr role="row" *ngFor="let objRC of recordList | filterColumn: grdFilters; let idx=index;">
<td class="text-center" *ngFor="let objGColumn of gridColumns; let idx=index;">
<span [textContent]="objRC[objGColumn.propertyKey]"></span>
</td>
</tr>
</tbody>
</table>
其中 gridColumns 将是显示列的数组。
dt-column-header 是一个包含搜索列文本框的组件。它有双向绑定 属性 过滤器,这将是网格中的过滤器
过滤器会像 grdFilters = {LastName: "123", FirstName: "456"}
我的烟斗是这样的。我参考了 https://www.code-sample.com/2018/07/angular-6-search-filter-pipe-table-by.html
@Pipe({
name: 'filterColumn'
})
export class GrdFilterPipe implements PipeTransform {
transform(items: any, filter: any, defaultFilter: boolean): any {
if (!filter){
return items;
}
if (!Array.isArray(items)){
return items;
}
if (filter && Array.isArray(items)) {
let filterKeys = Object.keys(filter);
if (defaultFilter) {
return items.filter(item =>
filterKeys.reduce((x, keyName) =>
(x && new RegExp(filter[keyName], 'gi').test(item[keyName])) || filter[keyName] == "", true));
}
else {
return items.filter(item => {
return filterKeys.some((keyName) => {
return new RegExp(filter[keyName], 'gi').test(item[keyName]) || filter[keyName] == "";
});
});
}
}
}
}
我的第一个问题是当 gridFilters 改变时管道没有调用。我不得不让它变得 不纯 这会影响性能。
另一个问题是管道在 {LastName: "123"}
或 {FirstName: "456"}
但是无法使用 {LastName: "123", FirstName: "456"}
OR {LastName: "", FirstName: "456"}
OR {LastName: "123", FirstName: ""}
快速回答:
"My first issue is pipe is not calling when gridFilters change":
推荐: 将管道保留为纯管道并重新分配 gridFilters
而不是修改它。换句话说,不要在 dt-column-header
组件中使用 ngModel,而是使用输入事件并重新分配 gridFilters
变量。
或(不推荐): 通过在 @Pipe
装饰师:
@Pipe({
name: 'searchFilter',
pure: false
})
请参阅此 StackBlitz DEMO 以及可用的示例代码。
"Another issue is pipe works fine with... But not working with":
问题出在管道的代码上:
return items.filter(item => {
return filterKeys.some((keyName) => {
return new RegExp(filter[keyName], 'gi').test(item[keyName]) || filter[keyName] == "";
});
});
显然您没有得到想要的结果。你没有提到你想要得到的结果的问题,你是什么意思 working/not working?根据您的需要编辑您的问题,我会更新我的答案。
详细解答
解释 pure/impure 管道:
您的管道是纯管道(在@Pipe 装饰器中不使用元数据pure: false
时的默认管道类型)。只有当原始输入值(字符串、数字、布尔值、符号)发生变化或对象引用(日期、数组、函数、对象)发生变化时,纯管道才会执行。
因此,您有 2 个选项作为解决方案:
方案一(推荐):
为了让您的管道在 gridFilters 更改时再次调用,您需要重新分配它而不是修改它。换句话说,不要在 dt-column-header
组件中使用 ngModel,而是使用输入事件并重新分配 gridFilters
变量。
方案二(不推荐):
通过在 @Pipe
装饰器中添加 pure: false
使您的管道成为 不纯管道 :
@Pipe({
name: 'searchFilter',
pure: false
})
这一次,您的管道将在每个组件更改检测周期中执行。 这也是不推荐此解决方案的原因,因为它会经常被调用,就像每次击键或鼠标移动一样频繁。
Angular Docs - Impure pipes 说:
With that concern in mind, implement an impure pipe with great care. An expensive, long-running pipe could destroy the user experience.