rxjs对我来说是非常具有挑战性的,我发现自己无法解决这个问题。我在堆栈上找到的最接近的解决方案是使用合并运算符。这是link
我正在用角度2工作。
我在html中有一个输入搜索字段
<input (keydown.enter)="setFocus()" id="search-box" name="input-box" class="search-box" type="text" placeholder="Client search" (focus)="clearWarnings()" />
用户在字段框中键入,该字段将在预设的延迟后触发相应的功能。用户也可以按Enter键(和搜索图标)来触发搜索。我的目标是,只要用户按下Enter键,反跳操作就不会触发搜索,因为它已经在运行。
到目前为止,这里是使用合并功能的代码,尽管它似乎无法按照我的意图工作。
ngAfterViewInit() {
this.currentMember = this.appHelpersService.getLocalStorageSearchedRim();
if (this.currentMember) {
this.searchService.changeSearchTerm(this.currentMember);
}
var waitTime = AppConstants.SEARCH_TEXT_WAITTIME;
const searchSource = document.getElementById("search-box");
const keydownStream = fromEvent(this.elementRef.nativeElement, 'keyup');
const inputStream = fromEvent(searchSource, "input");
const allStreams = merge(keydownStream, inputStream);
allStreams
.pipe(
map((event: KeyboardEvent | MouseEvent) => (<HTMLInputElement>event.target).value.trim()),
filter((searchTerm: string) => {
waitTime = Number(searchTerm) ? AppConstants.SEARCH_NUMERIC_WAITTIME : AppConstants.SEARCH_TEXT_WAITTIME;
return searchTerm.length >= 2;
}),
debounce(() => timer(waitTime)),
distinctUntilChanged()
)
.subscribe((searchTerm: string) => {
this.showProgressbar = true;
this.listSearchResults(searchTerm);
});
}
和回车键事件:
setFocus(): void {
const searchBox: HTMLElement = document.getElementById("search-box");
const searchTerm = (<HTMLInputElement>searchBox).value;
if (searchTerm && searchTerm.length > 0) {
this.listSearchResults(searchTerm);
}
searchBox.focus();
}
在我提到的解决方案中,所有合并在一起的事件都将触发该函数,但不一定要取消另一个正在等待的事件(反跳)。
感谢您的时间
答案 0 :(得分:1)
我认为您的代码段中存在一些错误
const keydownStream = fromEvent(this.elementRef.nativeElement, 'keyup');
应该是
const keyupStream = fromEvent(this.elementRef.nativeElement, 'keyUp');
您真的不需要另一个fromEvent
,因为您的keyupStream
已经具有input
的值
您输入的函数调用和搜索的“预先输入”函数调用必须以可观察的形式包装起来才能取消。
鉴于他们是您,您可以做类似
的操作const search$ = fromEvent(this.search.nativeElement, 'keyup').pipe(share());
const searchKeyEnter$ = search$.pipe(filter((e: KeyboardEvent) => e.keyCode === 13 || e.which === 13))
const searchText$ = search$.pipe(filter((e: KeyboardEvent) => e.keyCode !== 13 && e.which !== 13), debounceTime(500))
const mergeKeyDown = merge(searchText$.pipe(mapTo('search')), searchKeyEnter$.pipe(mapTo('enter')))
.pipe(
withLatestFrom(search$),
filter(([origin, data]) => data.target.value.length > 2),
distinctUntilChanged(),
switchMap(([origin, data]) => {
if (origin === 'search') {
console.log('search started')
return of('').pipe(delay(3000), tap(() => console.log('search call has finished')))
} else {
return of('').pipe(tap(() => console.log(' i got called from enter')));
}
})
).subscribe(() => { })
这里发生的事情是我们共享用户输入的事件
fromEvent(this.search.nativeElement, 'keyup').pipe(share());
以便我们分发它以创建和合成特定类型的新可观察物
仅使用Enter键的示例:
search$.pipe(filter((e: KeyboardEvent) => e.keyCode === 13 || e.which === 13))
我们使用mapTo,以便我们区分触发哪个事件。
当这些事件中的任何一个被触发时,我们要再次使用刚刚使用withLatestFrom从输入中更新的值。
现在,要取消任何正在进行的异步任务,可以使用switchMap运算符。
使用Observables时,一件大事就是创建它们,以便您可以重用和组成它们。
我创建了一个stackblitz,您可以进行分叉,并亲自尝试一下,请注意控制台。
https://stackblitz.com/edit/merging-events?file=src/app/app.component.ts
希望这会有所帮助!