【问题标题】:RXJS to handle two different events, where the first occurance must cancel the secondRXJS 处理两个不同的事件,其中第一次发生必须取消第二次
【发布时间】:2018-08-24 03:40:51
【问题描述】:

rxjs 对我来说非常具有挑战性,我发现自己一直在努力解决这个问题。我在堆栈上找到的最接近的解决方案是使用合并运算符。这是link

我正在使用 Angular 2。

我在 html 中有一个输入搜索字段

<input (keydown.enter)="setFocus()" id="search-box" name="input-box" class="search-box" type="text" placeholder="Client search" (focus)="clearWarnings()" />

用户在字段框中输入,将在预设延迟后触发相应的功能。用户也可以按下回车键(和搜索图标)来触发搜索。我的目标是每当用户按下回车键时,去抖不应该触发搜索,因为它已经在运行了。

这是迄今为止使用合并功能的代码,尽管它似乎不像我想要的那样工作。

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

在我提到的解决方案中,所有合并在一起的事件都会触发该功能,但不一定会取消正在等待的其他事件(去抖动)。

感谢您的时间

【问题讨论】:

  • 所以 Enter Key Press 应该是立即搜索,而“typeahead”应该被去抖动?
  • 正确,但要求如果用户按 Enter 键,则预输入不应触发该功能。如果 debounce 已经在运行,那么让 debounce 触发另一个搜索是没有意义的。

标签: angular rxjs


【解决方案1】:

我认为你的 sn-p 中有一些错误

const keydownStream = fromEvent(this.elementRef.nativeElement, 'keyup');

应该是

const keyupStream = fromEvent(this.elementRef.nativeElement, 'keyUp');

而且您真的不需要另一个 fromEvent,因为您的 keyupStream 已经具有来自 input 的值

您的 enter 函数调用和您的搜索“typeahead”函数调用必须包装在一个 observable 中才能取消它们。

鉴于他们是你可以做类似的事情

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

以便我们分发它以创建和组合特定类型的新可观察对象

只取回车键的例子:

search$.pipe(filter((e: KeyboardEvent) => e.keyCode === 13 || e.which === 13))

我们使用mapTo,因此我们可以区分触发了哪个事件。

当任何这些事件被触发时,我们希望再次重用刚刚使用 withLatestFrom 从输入更新的值。

现在,为了取消任何正在进行的异步任务,可以使用 switchMap 运算符。

使用 Observables 时的一件大事是创建它们,以便您可以重用组合它们

我创建了一个 stackblitz,你可以 fork 并自己尝试一下,注意控制台。

https://stackblitz.com/edit/merging-events?file=src/app/app.component.ts

希望这会有所帮助!

【讨论】:

  • 将在家里调查这个问题,因为工作中的 stackblitz 被阻止了。非常感谢 Nico,我会告诉你进展如何。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 2017-07-03
  • 1970-01-01
  • 2016-11-28
相关资源
最近更新 更多