我有一个搜索引擎,我需要注册可观察并获取下拉自动完成建议,但即使触发了可观察,我可以在点击内看到我似乎无法将列表加载到我的模板下拉列表中
这是我的代码:
<mat-form-field>
<mat-chip-grid #chipGrid aria-label="Value selection">
@for (fruit of fruits(); track $index) {
<mat-chip-row (removed)="remove(fruit)">
//logic for fow
</mat-chip-row>
}
</mat-chip-grid>
<input placeholder="Start typing to see suggestions" #fruitInput formControlName="value"
[matChipInputFor]="chipGrid" [matAutocomplete]="auto"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"/>
</mat-form-field>
<div *ngIf="getChipsValueDropdowns(select.value, i) | async as accounts">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let account of accounts"
[value]="account">{{account.name}}</mat-option>
</mat-autocomplete>
</div>
<mat-autocomplete #auto="matAutocomplete">
<mat-option> Loading ...</mat-option>
</mat-autocomplete>
在我的 ts 文件中我有函数:
getChipsValueDropdowns(key: string, index: number): Observable<Account[]> {
if (key === 'account') {
return this.registerAccountListener(key, index)
}
return of([])
}
registerAccountListener(key: string, index: number) {
const control: FormControl = this.formArray.controls[index].get('key') as FormControl
if (control.value === key) {
return this.accountService.searchAccounts('SHE').pipe(
debounceTime(300),
distinctUntilChanged(),
map((response: { body: Account[] | null }) => {
return response.body ?? []
}),
tap((accounts) => {
console.log('Emitting accounts:', accounts)
}),
)
}
return of([])
}
问题是你在模板中调用
getChipsValueDropdowns()
函数,并且每次该函数运行时都会返回一个新的 Observable。当 Observable 返回一个值时,异步管道会标记该组件进行检查并触发一个新的更改检测周期,该周期会再次调用该函数并重新启动该进程。这是非常糟糕的做法,因为它会触发大量请求,甚至可能引发无限循环。您已通过根据实际请求使用 distinctUntilChanged()
运算符解决了此问题,但它只能解决此问题的症状。
相反,您应该将表单中的
valueChanges
observable 与执行请求的 Observable 与 switchMap()
: 结合起来
export class YourComponent {
drowdownValues$ = yourFormGroup.controls.select.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap((value) => {
const control: FormControl = this.formArray.controls[index].get(
"key",
) as FormControl;
if (control.value === key) {
return this.accountService.searchAccounts("SHE").pipe(
map((response: { body: Account[] | null }) => {
return response.body ?? [];
}),
tap((accounts) => {
console.log("Emitting accounts:", accounts);
}),
);
}
return of([]);
}),
);
}
并在模板中使用 Observable,如下所示:
<div *ngIf="drowdownValues$ | async as accounts">