All Components

Debouncing Value Changes

By default, the update of an Input value is processed without delay.

However, changes in the input might trigger complex operations such as network requests. To handle such scenarios, implement a slight delay before the component accepts the new value.

The following example demonstrates how to apply an afterValueChanged directive to any component with a valueChange event. Under the hood, the implementation uses the debounceTime RxJS operator.

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <p>
      Start typing a number to see the debounce in action:
    </p>

    <kendo-numerictextbox
      (afterValueChanged)="onAfterValueChange($event)"
      (valueChange)="onValueChange($event)">
    </kendo-numerictextbox>

    <hr />

    <div>
      Value: {{ rawValue }}
    </div>

    <div>
      Debounced Value: {{ value }}
    </div>
  `
})

export class AppComponent {
  public rawValue = 0;
  public value = 0;

  public onValueChange(value: number): void {
    this.rawValue = value;
  }

  public onAfterValueChange(value: number): void {
    this.value = value;
  }
}
import { Directive, Input, HostListener, OnDestroy, Output, EventEmitter } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import { debounceTime } from 'rxjs/operators/debounceTime';

@Directive({
  selector: '[afterValueChanged]'
})
export class AfterValueChangedDirective implements OnDestroy {
  @Output()
  public afterValueChanged: EventEmitter<any> = new EventEmitter<any>();

  @Input()
  public valueChangeDelay = 300;

  private stream: Subject<any> = new Subject<any>();
  private subscription: Subscription;

  constructor() {
    this.subscription = this.stream
      .pipe(debounceTime(this.valueChangeDelay))
      .subscribe((value: any) => this.afterValueChanged.next(value));
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

  @HostListener('valueChange', [ '$event' ])
  public onValueChange(value: any): void {
    this.stream.next(value);
  }
}

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { InputsModule } from '@progress/kendo-angular-inputs';

import { AppComponent } from './app.component';
import { AfterValueChangedDirective } from './after-value-changed.directive';

@NgModule({
  bootstrap:    [AppComponent],
  declarations: [AppComponent, AfterValueChangedDirective],
  imports:      [
    BrowserModule,
    BrowserAnimationsModule,
    InputsModule
  ]
})
export class AppModule { }

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

In this article