RXJS для обработки двух разных событий, но первое, что происходит, должно отменить другое

rxjs довольно сложен для меня, и я застрял, пытаясь решить эту проблему. Наиболее близким решением, которое я нашел в стеке, является использование оператора слияния. Вот ссылка

Я работаю в угловых 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();
    }

В решении, которое я упомянул, все объединенные события вызовут функцию, но не обязательно отменят другое ожидающее событие (debounce).

Спасибо за время

1 ответ

Я думаю, что у вас есть ошибки в вашем фрагменте

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

должно быть

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

И тебе действительно не нужен другой fromEvent так как ваш keyupStream будет иметь значение из input

Вызов функции ввода и вызовы функции поиска "typeahead" должны быть обернуты в наблюдаемую, чтобы отменить их.

Учитывая, что они вы могли бы сделать что-то вроде

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 важно создать их так, чтобы вы могли их повторно использовать и создавать.

Я создал стек-блиц, который вы можете раскошелиться и попробовать, для себя обратите внимание на консоль.

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

Надеюсь это поможет!

Другие вопросы по тегам