Как остановить трубу, если значение входного элемента HTML не изменилось с помощью Rx JS? - PullRequest
0 голосов
/ 13 марта 2020

Я использую Rx JS с Angular 9. Я пытаюсь добавить привязку keyup к своему вводу, и если пользователь ввел новое значение, я хочу запустить HTTP-запрос.

I иметь этот код:

fromEvent(this.inputBox.nativeElement, 'keyup')
  .pipe(
    // wait 300 ms to start
    debounceTime(300),
    // if value is the same, ignore
    distinctUntilChanged(),
    // start connection
    switchMap(term => this.autocompleteService.search({term: myterm}))
  ).subscribe((result: any[]) => {
    console.log(result);
  });

Теперь Если я нажму клавишу со стрелкой влево (значение не изменится), autocompleteService.search() запустится.

Я прочитал в Rx JS документация disctinctUntilChanged() остановит поток труб. Но не сделал.

Я тоже пробовал этот код, но не работал:

distinctUntilChanged((prevent: HTMLInputElement, current: HTMLInputElement) =>
  prevent.value === current.value),

Как я могу остановить продолжение канала, если значение входного элемента HTML не изменилось?

Ответы [ 2 ]

2 голосов
/ 13 марта 2020

Оператор distinctUntilChanged выдает только тогда, когда текущее значение отличается от последнего, как вы уже знаете.

Однако, пожалуйста, обратите внимание на слово value .

Вы используете distinctUntilChanged, но на чем именно работает этот оператор?

fromEvent прослушивает событие keyup и, как и ожидалось, будет излучать объект KeyboardEvent.

Это можно доказать, добавив оператор tap в текущую реализацию:

fromEvent(this.inputBox.nativeElement, 'keyup')
 .pipe(
  // wait 300 ms to start
  debounceTime(300),
  tap(e => console.log(e)),
  // if value is the same, ignore
  distinctUntilChanged(),
  // start connection
  switchMap(term => this.autocompleteService.search({term: myterm}))
).subscribe((result: any[]) => {
console.log(result);
});

Так что distinctUntilChanged не будет выполнять глубокое сравнение объектов.

Вместо этого, извлеките значение с помощью оператора map, после чего оно должно работать как положено:

fromEvent(this.inputBox.nativeElement, 'keyup')
  .pipe(
    debounceTime(300),
    map(val => val.target.value),
    distinctUntilChanged(), 
    switchMap(val => this.search(val))
  ).subscribe((result) => {
    console.log(result);
  });
1 голос
/ 13 марта 2020

Вы уверены, что с fromEvent, вы сразу получите term? Я бы подумал, что вы получите Event (нажата клавиша, et c. Et c.).

Попробуйте:

fromEvent(this.inputBox.nativeElement, 'keyup').pipe(
  map(event => this.inputBox.nativeElement.value),
  debounceTime(300),
  distinctUntilChanged((prev: string, curr: string) => prev === curr),
  switchMap(term => this.autocompleteService.search({term: myterm})),
).subscribe((result: any[]) => {
  console.log(result);
});

Проблема с этим подходом что его нужно дважды отправить, чтобы выполнить сравнение с предыдущим значением в distinctUntilChanged, и если первый набранный символ был стрелкой влево, он будет подписан и отправит запрос.

Возможно, вы захотите попробовать оператор filter.

fromEvent(this.inputBox.nativeElement, 'keyup').pipe(
  map(event => this.inputBox.nativeElement.value),
  filter(term => /* don't emit if the term has weird characters that you can decide on */),
  debounceTime(300),
  switchMap(term => this.autocompleteService.search({term: myterm})),
).subscribe((result: any[]) => {
  console.log(result);
});

Я даже не думаю, что distinctUntilChanged нужен сейчас, так как отображение его на this.inputBox.nativeElement.value не будет поглощать клавиши со стрелками.

...