435

The change event is only called after the focus of the input has changed. How can I make it so that the event fires on every keypress?

<input type="text" [(ngModel)]="mymodel" (change)="valuechange($event)" />
{{mymodel}}

The second binding changes on every keypress btw.

1

13 Answers 13

735

I just used the event input and it worked fine as follows:

in .html file :

<input type="text" class="form-control" (input)="onSearchChange($event.target.value)">

in .ts file :

onSearchChange(searchValue: string): void {  
  console.log(searchValue);
}
Sign up to request clarification or add additional context in comments.

5 Comments

how do we delay for some time?
The (input) event is not supported in Edge and IE browsers. What is the alternative for this in Edge browser?
spent a lot of time on change detection and what not. In the end, found peace. Thank you for this! PS: My problem was related to angular [formGroup], and I was using (change) before finding this post. Didn't know that (input) will work.
many thanks, I noticed (change) event triggers on blur, whilst this one when you type.
@MahmoudHboubati this may come a bit late, but you could delay the search by setTimeout and store the return value of that function. And every time before you do it again, you can reset that delayed execution via clearTimeout: if (this.searchDelayHandle) clearTimeout(this.searchDelayHandle); this.searchDelayHandle = setTimeout(() => ..., 1000);
238

Use ngModelChange by breaking up the [(x)] syntax into its two pieces, i.e., property databinding and event binding:

<input type="text" [ngModel]="mymodel" (ngModelChange)="valuechange($event)" />
{{mymodel}}
valuechange(newValue) {
  mymodel = newValue;
  console.log(newValue)
}

It works for the backspace key too.

13 Comments

But when using the banana in a box syntax, it only changes the model, but you cant hook something on the change event.
That's a great answer for best two-way data binding. Should be the accepted answer!
backspace key is not updating the model
That solution is correct. However, be aware that ngModelChange is fired BEFORE the value updates. So the 'newValue' in this example contains the model WITHOUT the key you just pressed - so you don't have the updated model there. If you want to have the most recent model value, use the (keyup) event.
@SateeshKumarAlli which version of Angular do you have? For me it does detect backspace in Angular 6.1.3
|
157

The (keyup) event is your best bet.

Let's see why:

  1. (change) like you mentioned triggers only when the input loses focus, hence is of limited use.
  2. (keypress) triggers on key presses but doesn't trigger on certain keystrokes like the backspace.
  3. (keydown) triggers every time a key is pushed down. Hence always lags by 1 character; as it gets the element state before the keystroke was registered.
  4. (keyup) is your best bet as it triggers every time a key push event has completed, hence this also includes the most recent character.

So (keyup) is the safest to go with because it...

  • registers an event on every keystroke unlike (change) event
  • includes the keys that (keypress) ignores
  • has no lag unlike the (keydown) event

9 Comments

As mentioned in one of the answers, input event works really well. keyup is for sure one of the safest options however, input event is one step ahead of keyup. keyup unlike input, doesn't work if the value of textbox is changed by any other way e.g. binding.
Sagar, thank you very much. This should be the Accepted Answer as it is the only one to actually address (change) alongside a workaround and then some. The accepted answer totally sucks!
This should be the accepted and safest answer as it is native and gives you full control and it is very expressive, because everyone that reads it knows exactly when the event is fired.
@ThariqNugrohotomo No, it would not. Use (input) if you are looking for something like that.
(keyup) helped me with backspace keystroke, thank's a lot!
|
40
<input type="text" [ngModel]="mymodel" (keypress)="mymodel=$event.target.value"/>
{{mymodel}}

Update

https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event

Warning: Since this event has been deprecated, you should use beforeinput or keydown instead.

7 Comments

works, but strangely the backspace key isn't recognized as a keypress?
You might want to use keydown or keyup instead. Some keys just don't fire on keypress. See also stackoverflow.com/questions/4843472/…
I have tried keydown, keyup and change events but when the input is w the event handler reports to me empty string; when the input is we the event handler reports to me w as the input. Can you please explain why this behavior?
It's strange, but I'm getting an input lag on this where the value doesn't contain the typed value until the next keypress.
|
40

A different way to handle such cases is to use formControl and subscribe to its valueChanges when your component is initialized, which will allow you to use rxjs operators for advanced requirements like performing http requests, apply a debounce until user finish writing a sentence, take last value and omit previous value, etc.

import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

@Component({
  selector: 'some-selector',
  template: `
    <input type="text" [formControl]="searchControl" placeholder="search">
  `
})
export class SomeComponent implements OnInit {
  public searchControl: FormControl;
  public debounce: number = 400;

  ngOnInit() {
    this.searchControl = new FormControl('');
    this.searchControl.valueChanges
      .pipe(debounceTime(this.debounce), distinctUntilChanged())
      .subscribe(query => {
        console.log(query);
      });
  }
}

2 Comments

This is perfect. This keeps the chatty noise down when using this for async http requests. Also already sets up the change event listeners. Brilliant! Thanks!
In case of multiple controls, same code can be applied with FormGroup
23

The secret event that keeps angular ngModel synchronous is the event call input. Hence the best answer to your question should be:

<input type="text" [(ngModel)]="mymodel" (input)="valuechange($event)" />
{{mymodel}}

2 Comments

It does for me @AndreiDiaconescu
The (input) event is not supported in Edge and IE browsers. What is the alternative for this in Edge browser?
8
<input type="text" (keypress)="myMethod(myInput.value)" #myInput />

archive .ts

myMethod(value:string){
...
...
}

2 Comments

Welcome to SO Ulric, please explain how your code solves the problem.
6

For Reactive Forms, you can subscribe to the changes made to all fields or just a particular field.

Get all changes of a FormGroup:

this.orderForm.valueChanges.subscribe(value => {
    console.dir(value);
});

Get the change of a specific field:

this.orderForm.get('orderPriority').valueChanges.subscribe(value => {
    console.log(value);
  });

1 Comment

Note that it will only be triggered on blur
5

I managed to get this solved in Angular 11 by using the below code:

<input type="number" min="0" max="50" [value]="input.to" name="to"
        (input)="input.to=$event.target.value; experienceToAndFrom()">

And, the experienceToAndFrom() is a method in my component.

PS: I tried all the above solutions, but didn't work.

Comments

4

What you're looking for is

<input type="text" [(ngModel)]="mymodel" (keyup)="valuechange()" />
{{mymodel}}

Then do whatever you want with the data by accessing the bound this.mymodel in your .ts file.

Comments

4

In my case, the solution is:

[ngModel]="X?.Y" (ngModelChange)="X.Y=$event"

Comments

2

I've been using keyup on a number field, but today I noticed in chrome the input has up/down buttons to increase/decrease the value which aren't recognized by keyup.

My solution is to use keyup and change together:

(keyup)="unitsChanged[i] = true" (change)="unitsChanged[i] = true"

Initial tests indicate this works fine, will post back if any bugs found after further testing.

Comments

1

This question has been answered with multiple ways. However, if you would like to look at another way, specific to adding some delay before you take any action on change event then you can use the debounceTime() method with angular form valuechanges(). This code need to be added in ngOnInit() hook or create a seprate method and call it from ngOnInit().

  ngOnInit(): void {
    this.formNameInputChange();
  }

  formNameInputChange(){
    const name = this.homeForm.get('name'); // Form Control Name
    name?.valueChanges.pipe(debounceTime(1000)).subscribe(value => {
      alert(value);
    });
  }
  // this is reactive way..
  homeForm = this.fb.group({
    name:['']
  });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.