In AngularJS I can debounce a model by using ng-model options.
ng-model-options="{ debounce: 1000 }"
How can I debounce a model in Angular? I tried to search for debounce in the docs but I couldn't find anything.
https://angular.io/search/#stq=debounce&stp=1
A solution would be to write my own debounce function, for example:
import {Component, Template, bootstrap} from 'angular2/angular2';
// Annotation section
@Component({
selector: 'my-app'
})
@Template({
url: 'app.html'
})
// Component controller
class MyAppComponent {
constructor() {
this.firstName = 'Name';
}
changed($event, el){
console.log("changes", this.name, el.value);
this.name = el.value;
}
firstNameChanged($event, first){
if (this.timeoutId) window.clearTimeout(this.timeoutID);
this.timeoutID = window.setTimeout(() => {
this.firstName = first.value;
}, 250)
}
}
bootstrap(MyAppComponent);
And my html
<input type=text [value]="firstName" #first (keyup)="firstNameChanged($event, first)">
But I'm looking for a build in function, is there one in Angular?
HTML file:
TS file:
For anyone using lodash, it is extremely easy to debounce any function:
then just throw something like this into your template:
We can create a [debounce] directive which overwrites ngModel's default viewToModelUpdate function with an empty one.
Directive Code
How to use it
I solved this by writing a debounce decorator. The problem described could be solved by applying the @debounceAccessor to the property's set accessor.
I've also supplied an additional debounce decorator for methods, which can be useful for other occasions.
This makes it very easy to debounce a property or a method. The parameter is the number of milliseconds the debounce should last, 100 ms in the example below.
And here's the code for the decorators:
I added an additional parameter for the method decorator which let's you trigger the method AFTER the debounce delay. I did that so I could for instance use it when coupled with mouseover or resize events, where I wanted the capturing to occur at the end of the event stream. In this case however, the method won't return a value.
You can create an RxJS (v.6) Observable that does whatever you like.
view.component.html
view.component.ts
Updated for RC.5
With Angular 2 we can debounce using RxJS operator
debounceTime()
on a form control'svalueChanges
observable:Plunker
The code above also includes an example of how to throttle window resize events, as asked by @albanx in a comment below.
Although the above code is probably the Angular-way of doing it, it is not efficient. Every keystroke and every resize event, even though they are debounced and throttled, results in change detection running. In other words, debouncing and throttling do not affect how often change detection runs. (I found a GitHub comment by Tobias Bosch that confirms this.) You can see this when you run the plunker and you see how many times
ngDoCheck()
is being called when you type into the input box or resize the window. (Use the blue "x" button to run the plunker in a separate window to see the resize events.)A more efficient technique is to create RxJS Observables yourself from the events, outside of Angular's "zone". This way, change detection is not called each time an event fires. Then, in your subscribe callback methods, manually trigger change detection – i.e., you control when change detection is called:
Plunker
I use
ngAfterViewInit()
instead ofngOnInit()
to ensure thatinputElRef
is defined.detectChanges()
will run change detection on this component and its children. If you would rather run change detection from the root component (i.e., run a full change detection check) then useApplicationRef.tick()
instead. (I put a call toApplicationRef.tick()
in comments in the plunker.) Note that callingtick()
will causengDoCheck()
to be called.