13

I want to get a value from an input text after a few time (many millisecond or seconds) in angular 2, when a custom write an input but without waiting him to click a button.

I have tried this, but even when I use debounceTime, value is send in every keypress.

I try to learn about debounce and observable and this is what I understand, Can anyone please help me to fix my code:

component.html:

<md-card-title *ngIf="!edit">{{card.title}}</md-card-title>
 <input *ngIf="edit" type="text" [(ngModel)]="card.title" (ngModelChange)='rename()'/>

component.ts

newTitle: string;
modelChanged: Subject < string > = new Subject < string > ();

constructor()
this.modelChanged
  .debounceTime(500) //before emitting last event
  .distinctUntilChanged()
  .subscribe(model => this.newTitle = model);
}

rename(): void {
  this.renameRequest.emit(this.newTitle);
}
n00dl3
  • 21,213
  • 7
  • 66
  • 76
Salma
  • 187
  • 1
  • 2
  • 9

2 Answers2

11

Well, there is lot's of ways to achieve that, but here is one way :

<input *ngIf="edit" type="text" #input="ngModel" [(ngModel)]="card.title" (ngModelChange)='rename()'/>

And inside your class

newTitle : string;
@ViewChild('input') input;
constructor()

}

ngAfterViewInit(){
       this.input.valueChanges
             .pipe(debounceTime(500)) before emitting last event
             .pipe(distinctUntilChanged())
             .subscribe(model => (value)=>{
                   console.log('delayed key press value',value);
                    this.rename(value)
              });

}

rename(value): void {
    this.renameRequest.emit(value);
}

Here is the Plunker

You can even subscribe to modelChange like bellow :

ngAfterViewInit(){
       this.input.update // this is (modelChange)
             .pipe(debounceTime(500)) before emitting last event
             .pipe(distinctUntilChanged()) 
             .subscribe(model => (value)=>{
                   console.log('delayed key press value',value);
              });

}
Milad
  • 27,506
  • 11
  • 76
  • 85
  • yeh, the value is saved in @ViewChild('input') input but the function rename() is never called, have you any idea?? – Salma May 16 '17 at 11:27
  • i got this error : TypeError: Cannot read property 'valueChanges' of undefined . and when i add condition (if(this.input)) it work but the value is changing in every key press – Salma May 16 '17 at 13:30
  • i just remove (ngModelChange)='rename()' in html code, and it works perfectly, thank you @Milad – Salma May 16 '17 at 13:57
  • 5
    On more recent angular versions you need to `pipe()` it so it looks like : `this.input.valueChanges.pipe(debounceTime(500), distinctUntilChanged()).subscribe` – NeeL Nov 22 '18 at 02:24
  • It's giving `undefined` for `rename()`. I removed the `ngModelChange` from HTML and also removed `model` from `subscribe`, then it worked. – saberprashant Feb 02 '21 at 22:18
-1

Angular 12.2 + RxJS + lodash

If you're using lodash. $ npm i --save lodash

<input (keyup)="debouncedSearch($event)"/> 
import { debounce } from 'lodash';

...

  debouncedSearch = debounce(
        (event) => this.search(event.target.value),
        400
  )

  search(query: string){
    console.log(query)
  }

...
  <input (keyup)="debouncedSearch()" [(ngModel)]="theInput" /> 

Version with local model

If you have a local var to bind to, you can also do this:

It's more readable and you can set your var in ngOnInit or wherever you need to.

import { debounce } from 'lodash';

...

  theInput: string = ''

  debouncedSearch = debounce(this.search, 400)

  search(){
    console.log(this.theInput)
  }

...
Vlad Lego
  • 1,670
  • 1
  • 18
  • 19