Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2: Debounce (ngModelChange)?

Is there a way to debounce the template directive (ngModelChange)?

Or, alternatively, what is the least-painful way to do it a different way?

The closest answer I see is this: How to watch for form changes in Angular 2?

So, for example, I have a text input, I want to get onChange updates, but I want to debounce it down from every keystroke:

<input type="text" class="form-control" placeholder="Enter a value" name="foo" [(ngModel)]="input.event.value" (ngModelChange)="onFieldChange($event, input)"> 

Debounce onFieldChange()

like image 876
mtyson Avatar asked Dec 23 '16 23:12

mtyson


People also ask

What is debounce in angular?

Debouncing is the delay of a function/method execution or an action for a period of the specified time. During this specified time, calls to the method/function or action are collected and executes each one when the specified has elapsed.

What is NgModel and ngModelChange?

The NgModel class has the update property with an EventEmitter instance bound to it. This means we can't use (ngModelChange) without ngModel . Whereas the (change) event can be used anywhere, and I've demonstrated that above with the [value] property binding instead.

How do you use Ngmodeloptions?

The ng-model-options directive is used to control the binding of an HTML form element and a variable in the scope. You can specify that the binding should wait for a specific event to occur, or wait a specific number of milliseconds, and more, see the legal values listed in the parameter values below.


Video Answer


2 Answers

EDIT

In new version of Angular you can use updateOn in ngModelOption to set 'blur' for example. Link to angular.io documentation.

Code example :

<input [(ngModel)]="value"   [ngModelOptions]="{ updateOn: 'blur' }"   (ngModelChange)="updateOnlyOnBlur($event)">  

LEGACY

Here's the less painful way of debouncing keystrokes if you don't want to use the formcontrol approach.

search.component.html

<input type="text" placeholder="Enter a value" name="foo" [(ngModel)]="txtQuery" (ngModelChange)="onFieldChange($event)"> 

search.component.ts

    export class SearchComponent {               txtQuery: string; // bind this to input with ngModel          txtQueryChanged: Subject<string> = new Subject<string>();               constructor() {           this.txtQueryChanged             .debounceTime(1000) // wait 1 sec after the last event before emitting last event             .distinctUntilChanged() // only emit if value is different from previous value             .subscribe(model => {               this.txtQuery = model;                    // Call your function which calls API or do anything you would like do after a lag of 1 sec               this.getDataFromAPI(this.txtQuery);              });         }          onFieldChange(query:string){       this.txtQueryChanged.next(query);     } } 
like image 94
Sangram Nandkhile Avatar answered Sep 24 '22 17:09

Sangram Nandkhile


For RxJs 6+

The chosen answer won't work for RxJs 6+. Here is what you have to change:

The imports have to look like this:

import { debounceTime, distinctUntilChanged, Subject } from 'rxjs'; 

You need to call pipe:

// ... this.txtQueryChanged    .pipe(debounceTime(1000), distinctUntilChanged())    .subscribe(model => {        this.txtQuery = model;        // api call    });  // ... 

Take a look at this article for further reading.

like image 45
Willi Mentzel Avatar answered Sep 24 '22 17:09

Willi Mentzel