Angular как выполнить функцию после обновления поля. Но вместо того, чтобы делать это при каждом изменении, только после изменения 3 или 4 букв - PullRequest
0 голосов
/ 26 февраля 2020

У меня есть форма angular, где я хочу предложить пользователю, что он должен поместить на ввод в зависимости от того, что он пишет.

Я, очевидно, могу использовать директиву onChange и сделать вызов API для сервис, который делает предложения после каждого изменения. Но я думаю, что это не очень хорошая реализация, так как я буду делать столько звонков, сколько писем пишут пользователи (а также возможные опечатки). Таким образом, идея состоит в том, чтобы сделать эту функцию onChange, которая выполняет вызов API только после X изменений в поле. Как я могу это сделать? Как я могу проверить, достаточно ли изменилось поле, чтобы сделать еще один вызов API для получения новых предложений?

Ответы [ 2 ]

2 голосов
/ 26 февраля 2020

Прежде всего, вы должны прослушать изменения в поле ввода формы. Если вы используете реактивные Angular формы, то вы можете использовать свойство valueChanges formControl для прослушивания изменений. В противном случае вы должны использовать декоратор @ViewChild, чтобы получить ссылку на элемент ввода в файле TS, а затем прослушать изменения, используя функцию RX JS fromEvent.

Я использовал RX JS Функция fromEvent для демонстрации. Не стесняйтесь изменять его в соответствии со своими потребностями.

export class AppComponent implements OnInit {
  @ViewChild('textbox', { static: true }) textbox: ElementRef<HTMLInputElement>;

  ngOnInit() {
    /**
     * If you are using Reactive form, then use
     * form.get('<form-control-name>').valueChanges
     */
    const inputChanges$ = fromEvent(this.textbox.nativeElement, 'keyup');
    inputChanges$
      .pipe(
        // remove the below map operator if you are using Reactive forms formControl
        map(event => (event.target as HTMLInputElement).value),
        debounceTime(500),
        distinctUntilChanged(),
        switchMap(val => {
          // perform the http call for your service API like below
          // return this.http.get(`service.com/get?search=${val}`)
          return of(`sevice api all for: ${val}`);
        })
      )
      .subscribe(console.log)
  }
}

В приведенном выше примере все тяжелые операции выполняются этими 3 операторами RX JS debounceTime, distinctUntilChanged и switchMap.

  1. debounceTime:

Этот оператор фильтра просто выдает значение только через определенный промежуток времени, и если в течение этого промежутка времени генерируется несколько значений , только последнее значение возвращается. Например, если для debounceTime установлено значение 500 мс (как в нашем случае), через этот оператор фильтра проходит только последнее значение, выбрасываемое на каждые 500 мс. Для получения дополнительной информации посетите Rx js Официальные документы .

debounceTime - лучшее решение, чем подсчет количества измененных букв, чтобы предотвратить вызов API для каждого отдельного изменения. Кроме того, не увеличивайте denounceTime слишком сильно, так как это может испортить впечатление пользователя.

diverUntilChanged:

Как следует из названия, значение проходит через этот оператор фильтра, только если последнее полученное значение отличается от предыдущего значения. Для получения дополнительной информации посетите Rx js Официальные документы .

switchMap:

Это оператор отображения более высокого порядка, в том смысле, что он возвращает наблюдаемое для данного входа. Это особенно полезно в нашем случае, так как для каждого изменения значения входного элемента нам нужно обратиться к API бэкэнд-сервиса, чтобы получить некоторые значения для предложения. Наиболее интересной частью этого оператора является то, что, когда он получает новое значение, в то время как асинхронный вызов службы c продолжается для предыдущего значения, он отменяет предыдущий запрос и отправляет новый запрос для самого последнего полученного значения.

Я настоятельно рекомендую вам go в этой статье , как много вещей происходит здесь, когда используется опреатор switchMap, и я не смогу объяснить все здесь. Важно, чтобы вы понимали концепцию этого оператора.

Помните, не подписывайтесь вручную на наблюдаемое внутри оператора switchMap . Этот оператор RX JS автоматически подписывается на новую заметку и отменяет подписку на старую наблюдаемую.

Вы можете просмотреть код soure для этого примера в моем примере Stackblitz app .

Правки : обновлены ссылки и ссылки

0 голосов
/ 26 февраля 2020

Как прокомментировал другой пользователь, лучше воспользоваться оператором debounceTime, если вы хотите отложить вызовы API, поскольку пользователь печатает. Однако, если вы хотите делать это каждые n изменений, вы можете использовать оператор tap и подсчитать, сколько раз испускается наблюдаемое.

<input type="text" [formControl]="foo">
private count = 0;
private n     = 3;
public foo    = new FormControl('');

ngOnInit() {
 this.foo.valueChanges.pipe(
   tap(() => this.count++)
 ).subscribe(() => if (this.count % this.n === 0) { console.log('call api'); }
}
...