使用observable,我想过滤并显示一个列表。仅当用户开始键入时才会触发输入event
。因此,列表不会显示在第一位。在this.filterLocation$
开始触发之前,如何为可观察的inputEvent
分配默认值?
模板
<ng-template ngFor let-location [ngForOf]="filterLocation$ | async">
<a mat-list-item href="#">{{location}}</a>
</ng-template>
组件
ngAfterViewInit() {
const searchBox = document.querySelector('#search-input');
this.filterLocation$ = fromEvent(searchBox, 'input')
.pipe(
map((e: any) => {
const value = e.target.value;
return value ? this.locations
.filter(l => l.toLowerCase().includes(value.toLowerCase()))
: this.locations;
}),
startWith(this.locations)
)
}
}
使用startWith
可以使列表最初显示。但是抛出了以下错误:
错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后发生了变化。上一个值:&#39; ngForOf:null&#39;。当前值:&#39; ngForOf:name1,name2&#39;。
答案 0 :(得分:3)
可以使用spring.batch.job.enabled=false
运算符向具有startWith
运算符的observable提供初始值,因为现在已删除的答案中已经提到过。
问题是在filterLocation$
评估为filterLocation$ | async
后,null
分配得太晚了。由于更改发生在相同的tick上,因此会导致更改检测错误(尽管ExpressionChangedAfterItHasBeenCheckedError
可能会被视为警告,如果它出现的话)。
解决方案是在触发更改检测之前将代码从ngAfterViewInit
移至ngOnInit
。
这并不总是可行的。另一种方法是异步提供一个值,因此它不会干扰初始变化检测。
通过delay
运算符延迟整个observable(用户输入的可接受解决方案,因为它不是时间关键):
this.filterLocation$ = fromEvent(searchBox, 'input')
.pipe(
map((e: any) => {
const value = e.target.value;
return value ? this.locations
.filter(l => l.toLowerCase().includes(value.toLowerCase()))
: this.locations;
}),
startWith(this.locations),
delay(0)
)
或者使初始值与调度程序异步:
import { asyncScheduler } from 'rxjs'
...
this.filterLocation$ = fromEvent(searchBox, 'input')
.pipe(
map((e: any) => {
const value = e.target.value;
return value ? this.locations
.filter(l => l.toLowerCase().includes(value.toLowerCase()))
: this.locations;
}),
startWith(this.locations, asyncScheduler)
)