angular - mat-autocomplete 不使用 observable 过滤
问题描述
我有两个反应 Angular 形式的 mat-autocomplete 下拉菜单(Angular 和 Angular Material v12)。
一个作品。它从服务中提取一组对象,并且不包括选项的 Observable。它的开发与示例类似。另一个是订阅下拉选项的 observable,它们会显示,但无法过滤。我没有看到任何错误。
我的假设是过滤器在数据存在之前触发,或者过滤器的应用方式存在其他问题。数据显示得很好 - 我无法输入和过滤。
我对可观察代码的设置略有不同,以允许 API 上的订阅在过滤器上的订阅之前触发并比较唯一 ID。它似乎没有奏效。我无法确定代码的哪一部分失败了。我试过用可观察的重复工作代码,但它不能以相同的方式过滤类型(需要两个参数),我被困在那里。
也许有一种方法可以简化我的订阅?我明白发生了什么,但我观察到的经验很轻松。相关代码如下:
工作模板:
<mat-grid-tile-header>
Waste Type
</mat-grid-tile-header>
<mat-form-field appearance="standard">
<mat-label>Waste Type</mat-label>
<input
tabindex="2"
#waste_type
matInput
[matAutocomplete]="waste_type_auto"
placeholder="Choose a Waste Type"
class="input"
type="text"
formControlName="waste_type"
[ngClass]="{'is-success' : collectForm.get('waste_type').valid && collectForm.get('waste_type').dirty, 'is-danger' : !collectForm.get('waste_type').valid }"
aria-label="Waste Type">
<mat-autocomplete #waste_type_auto="matAutocomplete">
<mat-option *ngFor="let waste_type of filteredWaste_Types$ | async" [value]="waste_type.name">
<img class="example-option-img" aria-hidden [src]="waste_type.icon" height="25">
<span>{{ waste_type.name }}</span>
</mat-option>
</mat-autocomplete>
<mat-hint [hidden]="collectForm.get('waste_type').valid" align="end">Waste type (e.g., Recycling) is required</mat-hint>
</mat-form-field>
非工作模板(几乎相同):
<mat-grid-tile-header>
Tare
</mat-grid-tile-header>
<mat-form-field appearance="standard">
<mat-label>Waste Container</mat-label>
<input
tabindex="4"
#tare_container
placeholder="Enter Container"
matInput
[matAutocomplete]="tare_auto"
class="input"
type="text"
formControlName="tare_container"
[ngClass]="{'is-success' : collectForm.get('tare_container').valid && collectForm.get('tare_container').dirty, 'is-danger' : !collectForm.get('tare_container').valid }"
aria-label="Tare Container">
<mat-autocomplete #tare_auto="matAutocomplete">
<mat-option *ngFor="let tare of filteredTares$ | async" [value]="tare.container_name">
<img class="example-option-img" aria-hidden [src]="tare.container_icon" height="25">
<span>{{ tare.container_name }}</span>
</mat-option>
</mat-autocomplete>
<mat-hint [hidden]="collectForm.get('tare_container').valid" align="end">Tare (e.g., Lg Compost Bin) is required</mat-hint>
</mat-form-field>
.ts 用于两个过滤器
filteredWaste_Types$: Observable<Waste_Type[]>;
filteredTares$: Observable<Tare[]>;
// Working Value Changes Subscription
this.filteredWaste_Types$ = this.collectForm.get('waste_type').valueChanges
.pipe(
startWith(''),
map(value => this._filteredWaste_Types(value))
);
// Non-Working Value Changes Subscription
this.filteredTares$ = zip(
this.collectForm.get('tare_container').valueChanges
.pipe(
startWith('')),
this.ts.tares,
)
.pipe(
map(([value, tares]) => {
const filtered = value ? this._filteredTares(value, tares) : tares;
return filtered;
})
);
// Working Filter
private _filteredWaste_Types(value: string): Waste_Type[] {
const filterValue = value.toLowerCase();
return this.wts.waste_types.filter(waste_type => waste_type.name.toLowerCase().includes(filterValue));
}
// Non-Working Filter
private _filteredTares(value: string, tares: Tare[]): Tare[] {
const filterValue = value.toLowerCase();
return tares.filter(tare => tare.container_name.toLowerCase().includes(filterValue));
}
工作废物类型服务:
waste_types: Waste_Type[] = [
{
name: 'Batteries',
icon: './assets/img/battery_icon.png'
},
{
name: 'Cardboard',
icon: './assets/img/cardboard_icon.png'
},
{
name: 'Compost',
icon: './assets/img/compost_icon.png'
}];
非工作皮重服务:
public cachedTares: Tare[] = [];
public get tares() {
return this.api.getTares()
.pipe(
map((tares) => {
this.cachedTares = tares;
return tares;
})
);
};
提供非工作服务的 API:
public getTares() {
const uri = '/containers';
if (this.isOnline) {
return this.http.get<Tare[]>(uri, this.httpOptions).pipe(
map(this.cacheGetRequest(uri)),
);
} else {
const result = this.getCachedRequest<Tare[]>(uri);
return new BehaviorSubject(result).asObservable();
}
}
每个的数据结构几乎相同:
export interface Waste_Type {
name: string;
icon: string;
}
export interface Tare {
id: number;
container_name: string;
container_icon: string;
container_weight: number;
}
解决方案
我想你只需要用zip
rxjscombineLatest
运算符替换。
区别在于:
combineLatest操作符的行为与zip类似,但zip仅在每个 Observable源之前发出过一个项目时才会发出, 而combineLatest会在任何源 Observable 发出一个项目时发出一个项目
这意味着filteredTares$
当您收到来自的响应时,您的 observable 只会发出一次值TareService
。之后,即使valueChanges
发出新值,它也会保持沉默(即使您输入input
)
this.filteredTares$ = combineLatest([
this.collectForm2.get('tare_container').valueChanges.pipe(startWith('')),
this.ts.tares,
])
...
推荐阅读
- mongodb - 如何使用中间表使用 $lookup 管道查找值
- julia - 在 Julia 中添加基本函数与使用唯一函数名
- java - 聚类 Mapbox Android SymbolManager 注解
- types - 如何正确处理bucklescript中原始js函数调用的结果类型
- node.js - NodeJS:TypeError:res.redirect 不是函数
- c++ - 符号“cout”无法解析,#include 预计 Eclipse 中的简单数学程序会出现“FILENAME”错误
- gulp - gulp - internalBinding 未定义
- react-native - 使用快照笑话测试配置反应原生 expo 应用程序
- mysql - MySQL - GROUP BY,分组时只选择第一行
- http - 除了 HTTP 标头中的接受语言之外,还有其他方法可以确定客户端语言环境吗?