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()
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.
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.
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.
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); } }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With