Tanzeel
Tanzeel

Reputation: 5018

How detect changes in an input field as we type-in [Angular]

I'm new to Angular. I'm trying few simple things. I've an Input field. I just want to detect changes. I want to call some code whenever I type into the field. I checked these articles:

  1. Documentaion: Angular - onChanges
  2. What is the difference between OnChanges and DoCheck in Angular 2?
  3. Documentaion: Angular - Lifecycle hooks
  4. Stackoverflow: In Angular 4 the hook ngOnChanges is not firing on input

Here's my code:

my-component.component.html

<input [(ngModel)]="text">

my-component.component.ts

import { Component, OnInit, DoCheck } from '@angular/core';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent implements OnInit, DoCheck {

  text="hello world";

  constructor() { }

  ngOnInit() {
  }

  ngOnChanges(changes: SimpleChanges) {
    // changes.prop contains the old and the new value...
  }

  // ngDoCheck() { // TRIED THIS ALSO
  //   console.log("Changes detected")
  // }
}

Two important information:

  1. I tried DoCheck also, but this is not what I want. I want to see if only input field's value is changed or not. But ngDoCheck will be called after every slight change in the rest of the components also as it is using zone.js ( i read this somewhere).

  2. I can't use (keydown) also as I want to implement validation code later. I want validation to happen as I type-in. But with keydown, i noticed that I've to trigger validation code with some key-press even after the entered value is valid, let's say a Date/Time.

Keeping above two points in mind, please correct me. Here's the stackblitz.

Upvotes: 14

Views: 91772

Answers (5)

tastytim
tastytim

Reputation: 341

in html

<input type="text" (input)="onChange($event.target.value)">

in component

onChange(value:string){
console.log(value) }

Upvotes: 0

Kari F.
Kari F.

Reputation: 1434

I think all the above answers are correct. I like the getter-setter method though it adds several lines of code. Just in case you'd like to test a third way of tracking changes y forked your code: https://stackblitz.com/edit/angular-myrrqo

It uses @ViewChildren and a subscription to the valueChanges observable:

export class MyComponentComponent implements AfterViewInit  {

  text="hello world";
  second="hi angular";

  @ViewChildren(NgModel) myInputRef: QueryList<NgModel>;

  ngAfterViewInit() {
    this.myInputRef.forEach(ref =>
      ref.valueChanges.subscribe(val =>
        console.log(`${ref.name}'s value changed to ${val}`)
      )
    );
  }
}

In the template:

<input [(ngModel)]="text" name="firstInput">
<input [(ngModel)]="second" name="secondInput">

I added a second input element to show that if you have more than one element with two-way binding you have to use @ViewChildren. If you only had one element you could use @ViewChild(NgModel) myFirstInput: NgModel; and the code would be even simpler.

Upvotes: 2

Aymen TAGHLISSIA
Aymen TAGHLISSIA

Reputation: 1925

you can use input() : Exemple :

HTML :

<input [(ngModel)]="text" (input)="sendTheNewValue($event)">

TS:

let value:string;

sendTheNewValue(event){
this.value = event.target.value;
}

in your exemple : HTML :

<input [(ngModel)]="text" (input)="change($event)">
<div>the input value is : {{text}}</div>

TS:

import { Component, OnInit, DoCheck, SimpleChanges, OnChanges, Input   } from '@angular/core';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent implements OnInit, OnChanges  {

  text="hello world";

  @Input() name: String = "abc"

  constructor() { }

  ngOnInit() {
  }

  ngOnChanges(changes: SimpleChanges) {
    // changes.prop contains the old and the new value...
    console.log("Changes detected");
  }

  change(event){
    this.text = event.target.value;
  }

  // ngDoCheck() {
  //   console.log("Changes detected");
  // }
}

Upvotes: 28

kacase
kacase

Reputation: 2899

Angular handles the change detection itself. You just need to hook into the logic when it happens. In most cases this will be preferable to using eventlisteners, which are proposed by most other answers in this thread.

Whenever your input is changed, angular accesses the variable the string is set in.

One way to do something when the variable changes would be to use a getter and setter.

  // create an internal variable (do not change manually)
  private _text;

  // getter function, called whenever the value is accessed
  get text(){
    console.log("the value was accessed")
    return this._text
  }

  // setter function, called whenever the value is set
  set text(text){
    this._text = text
    console.log("the value was set")
  }

I also edited your stackblitz to include an example. https://stackblitz.com/edit/angular-6qvlrh

Everything else remains the same. And you just have to use ngModel on text.

<input [(ngModel)]="text">

Upvotes: 5

Gopinath
Gopinath

Reputation: 4957

These 2 changes are required to track the changes to input:

  1. Update the component template to bind value and specify (change) event.
  2. Update the component script to specify onChange method.

Working solution:

1. my-component.component.html

<input [(value)]="text" (change)="onChange($event)">

2. my-component.component.ts

import { Component, OnInit, DoCheck } from '@angular/core';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent {

  text="hello world";
  constructor() { 
    console.log("Text = " + this.text)
  }

  onChange(event: any) {
       this.text = event.target.value;
       console.log("New value = " + event.target.value)
  };
}

Upvotes: 2

Related Questions