RXJS处理两个不同的事件,但首先发生的事件必须取消另一个事件

时间:2018-08-24 03:40:52

标签: angular rxjs

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();
    }

在我提到的解决方案中,所有合并在一起的事件都将触发该函数,但不一定要取消另一个正在等待的事件(反跳)。

感谢您的时间

1 个答案:

答案 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

希望这会有所帮助!