Michel
Michel

Reputation: 23615

How to implement debounceTime the Angular way

I'm implementing debounceTime in an autocomplete scenario.

I want to use the debounceTime to limit the number of calls to the server. Google gives me 3 potential solutions, for which I pasted the code below.

All of them however, seem to have some drawbacks in my opinion, so I am looking for the most "Angular" way of implementing it.

  1. fromEvent(document.getElementById('myelement'), 'mouseover').pipe(
       debounceTime(1000),
       map(data => data.srcElement)
    ).subscribe(val => console.log(val)); 
    

This strikes me as "non-Anular'ish" as the component has a reference to element ID's in the HTML. This creates a dependency from the class to the HTML, in which I already have on the other way around. And it looks like plain JS in stead of "Angular'ish".

  1. this.bookId.valueChanges.pipe(
      debounceTime(1000),
      switchMap(id => {
        console.log(id);
        return this.bookService.getBook(id);
      })
    ).subscribe(res => this.book = res); 
    

This one looked the most "Anular'ish", with a subscription on the data-property in the class (bookId), but it needs reactive forms as I understand, which we do not use (not against it, so this is a possibility for us).

  1. this.subject
      .pipe(debounceTime(500))
      .subscribe(() => {
        this.formGroup.controls.name.setValidators([ Validators.minLength(5) ]);
        this.formGroup.controls.name.updateValueAndValidity();
      });
    
    onKeyUp(): void {
      this.subject.next();
    }
    
     <input type="text" formControlName="name" (keyup)="onKeyUp()"> 
    

    This also doesn't look very "Angular'ish" because it looks like plain JavaScript that I catch and process DOM events. I thought that, in my opinion, this is not an Angular way of working?

Upvotes: 1

Views: 78

Answers (1)

Pankaj Shukla
Pankaj Shukla

Reputation: 2672

Options 2 and 3 look Angular'ish. However, you can make option 1 also angularish.

Angular has a concept of ViewChild to get DOM elements into component class. You can use Angular's ngAfterViewInit life-cycle hook to get the DOM element. One way would be this:

@ViewChild ('myName', { static: false }) myName;

  ngAfterViewInit() {
    fromEvent(this.myName.nativeElement, 'mouseover').pipe(debounceTime(1000), 
    tap(data => console.log(data)),
    map(data => data.srcElement)
    ).subscribe(val => console.log(val)); 
  }

You can see this stackblitz for more details: https://stackblitz.com/edit/angular-fotgbf

Upvotes: 1

Related Questions