Angular 7 双向绑定:以数组作为参数的管道无法按预期工作
Angular 7 two-way binding: pipe taking an array as argument does not work as expected
我写了一个 Angular 7 管道,它有两个参数:一个要过滤的数组和一个匹配过滤器的数组。
import { Pipe, PipeTransform } from '@angular/core';
import { Order } from '../models';
@Pipe({
name: 'filterOrdersByDate'
})
export class CapacityOrderPipe implements PipeTransform {
transform(orders: Order[], periods: string[]): Order[] {
if (!orders) return [];
if (!periods.length) return orders;
return orders.filter(function(order: Order) {
for (var i=0; i<periods.length; i++) if (order.crossId.indexOf(periods[i])>-1) return true;
return false;
});
}
}
orders 是一个订单数组,如 Order 模型中所定义。每个订单都有一个crossId 属性。这是表示开始日期的字符串数组。
在我的 component.ts 中,我使用此方法 add/remove 来自周期数组的日期:
toggleOrder(date: string) {
let i = this.filters.orders.indexOf(date);
(i<0)? this.filters.orders.push(date) : this.filters.orders.splice(i, 1);
}
这是涉及的component.html代码:
<mat-list class="list">
<mat-list-item *ngFor="let o of (data.orders | filterOrdersByDate : filters.orders)">
<mat-divider></mat-divider>
<h3 mat-line>Order: {{o.group}}-{{o.number}}</h3>
...
</mat-list-item>
</mat-list>
...
<div *ngFor="let f of filters">
<mat-checkbox color="primary" [indeterminate]="false" (change)="toggleOrder(f.date)">{{f.date}}</mat-checkbox>
</div>
当我切换 component.html 中的复选框时,toggleOrder() 方法在过滤器数组中添加或删除日期。所以,我希望管道会过滤 data.orders 数组。不幸的是,这不起作用。我花了 2 个小时寻找解决方案,我发现,如果我将过滤器数组长度传递给管道,一切都会按预期进行。因此,似乎 Angular 将双向绑定设置为过滤器数组长度,而不是过滤器数组本身。
这是如何运作的?我希望 Angular 为组件 class 中定义的每个属性设置双向绑定:字符串、数组、数字等。但是管道不监听数组内容的变化。只有当我将数组长度传递给管道时,它才有效。但是,如果我有一个使用字符串而不是数组来过滤数据的管道,它就可以完美地工作。
如果您查看 Angular docs it talks about scenarios such as these. It discourages 管道由于性能不佳而以这种方式在数组上运行。
您正在尝试通过以下两种方式之一实现的目标。
您可以将管道更新为 'impure' 管道:
@Pipe({
name: 'filterOrdersByDate',
pure: false
})
或者您可以将其保留为纯管道并允许 Angular 通过每次重新分配数组值来利用内置的更改检测来获取您的更改。
toggleOrder(date: string) {
let i = this.filters.orders.indexOf(date);
(i<0)? this.filters.orders.push(date) : this.filters.orders.splice(i, 1);
this.filters.orders = this.filters.orders.slice(0);
}
正如最初所述,这不是执行此任务的最佳方式。我会坚持 Angular 的建议,并将此管道移至可以从您的 toggleOrder
方法调用的方法。
The Angular team and many experienced Angular developers strongly
recommend moving filtering and sorting logic into the component
itself. The component can expose a filteredHeroes or sortedHeroes
property and take control over when and how often to execute the
supporting logic. Any capabilities that you would have put in a pipe
and shared across the app can be written in a filtering/sorting
service and injected into the component.
我写了一个 Angular 7 管道,它有两个参数:一个要过滤的数组和一个匹配过滤器的数组。
import { Pipe, PipeTransform } from '@angular/core';
import { Order } from '../models';
@Pipe({
name: 'filterOrdersByDate'
})
export class CapacityOrderPipe implements PipeTransform {
transform(orders: Order[], periods: string[]): Order[] {
if (!orders) return [];
if (!periods.length) return orders;
return orders.filter(function(order: Order) {
for (var i=0; i<periods.length; i++) if (order.crossId.indexOf(periods[i])>-1) return true;
return false;
});
}
}
orders 是一个订单数组,如 Order 模型中所定义。每个订单都有一个crossId 属性。这是表示开始日期的字符串数组。
在我的 component.ts 中,我使用此方法 add/remove 来自周期数组的日期:
toggleOrder(date: string) {
let i = this.filters.orders.indexOf(date);
(i<0)? this.filters.orders.push(date) : this.filters.orders.splice(i, 1);
}
这是涉及的component.html代码:
<mat-list class="list">
<mat-list-item *ngFor="let o of (data.orders | filterOrdersByDate : filters.orders)">
<mat-divider></mat-divider>
<h3 mat-line>Order: {{o.group}}-{{o.number}}</h3>
...
</mat-list-item>
</mat-list>
...
<div *ngFor="let f of filters">
<mat-checkbox color="primary" [indeterminate]="false" (change)="toggleOrder(f.date)">{{f.date}}</mat-checkbox>
</div>
当我切换 component.html 中的复选框时,toggleOrder() 方法在过滤器数组中添加或删除日期。所以,我希望管道会过滤 data.orders 数组。不幸的是,这不起作用。我花了 2 个小时寻找解决方案,我发现,如果我将过滤器数组长度传递给管道,一切都会按预期进行。因此,似乎 Angular 将双向绑定设置为过滤器数组长度,而不是过滤器数组本身。
这是如何运作的?我希望 Angular 为组件 class 中定义的每个属性设置双向绑定:字符串、数组、数字等。但是管道不监听数组内容的变化。只有当我将数组长度传递给管道时,它才有效。但是,如果我有一个使用字符串而不是数组来过滤数据的管道,它就可以完美地工作。
如果您查看 Angular docs it talks about scenarios such as these. It discourages 管道由于性能不佳而以这种方式在数组上运行。
您正在尝试通过以下两种方式之一实现的目标。
您可以将管道更新为 'impure' 管道:
@Pipe({
name: 'filterOrdersByDate',
pure: false
})
或者您可以将其保留为纯管道并允许 Angular 通过每次重新分配数组值来利用内置的更改检测来获取您的更改。
toggleOrder(date: string) {
let i = this.filters.orders.indexOf(date);
(i<0)? this.filters.orders.push(date) : this.filters.orders.splice(i, 1);
this.filters.orders = this.filters.orders.slice(0);
}
正如最初所述,这不是执行此任务的最佳方式。我会坚持 Angular 的建议,并将此管道移至可以从您的 toggleOrder
方法调用的方法。
The Angular team and many experienced Angular developers strongly recommend moving filtering and sorting logic into the component itself. The component can expose a filteredHeroes or sortedHeroes property and take control over when and how often to execute the supporting logic. Any capabilities that you would have put in a pipe and shared across the app can be written in a filtering/sorting service and injected into the component.