4

I'm trying to call function ngOnChanges() in my Angular 5.x component whenever the variable this.test in component lifecycle or in template is changed but it's not working, ngOnChanges() function is not called anytime. Please can someone help me?

src/app.ts:

import {Component, NgModule, Input, OnChanges, SimpleChanges} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="text" placeholder="Test field" value="{{ test }}">
    </div>
  `,
})
export class App implements OnChanges {
  @Input() test: string;
  name: string;
  constructor() {
  }

  ngOnChanges(changes: SimpleChanges) {
    console.log('ngOnChanges');

    if (changes.test && !changes.test.isFirstChange()) {
      // exteranl API call or more preprocessing...
    }

    for (let propName in changes) {
      let change = changes[propName];
      console.dir(change);
      if(change.isFirstChange()) {
        console.log(`first change: ${propName}`);
      } else {
        console.log(`prev: ${change.previousValue}, cur: ${change.currentValue}`);
      }
    }
  }


}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

Live preview: https://plnkr.co/edit/ZHFOXFhEkSv2f1U3lehv

Thanks a lot!

Jan Elznic
  • 189
  • 1
  • 1
  • 8
  • I'm seeing Template parse errors in your linked plunker. It doesn't like your `ngModel` usage – Chic Feb 07 '18 at 00:40

2 Answers2

7

Input properties provide a mechanism for a parent component to pass data to a child component. They are NOT meant to pass data from a template to its component.

And only changes to that input property defined by the PARENT generate the onChanges method.

I updated the plunker to fix the missing FormsModule and add a child component to demonstrate how to use the input property and onChanges lifecycle hook:

https://plnkr.co/edit/1JF0wV28HnjXDZxMSifY?p=preview

Child Component

@Component({
  selector: 'my-child',
  template: `
    <div>
      <input type="text" [(ngModel)]="test" placeholder="Test field">
    </div>
  `,
})
export class ChildComponent implements OnChanges {
  @Input() test: string;
  name: string;
  constructor() {  }

  ngOnChanges(changes: SimpleChanges) {
    console.log('in ngOnChanges');
    if (changes.test && !changes.test.isFirstChange()) {
      // exteranl API call or more preprocessing...
    }

    for (let propName in changes) {
      let change = changes[propName];
      console.dir(change);
      if(change.isFirstChange()) {
        console.log(`first change: ${propName}`);
      } else {
        console.log(`prev: ${change.previousValue}, cur: ${change.currentValue}`);
      }
    }
  }
}

Parent component

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <my-child [test]='parentTest'></my-child>
      <button (click)='onClick()'>Change Value</button>
    </div>
  `,
})
export class App {
  parentTest: string;
  name: string;
  counter = 1;

  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }

  onClick() {
    this.parentTest = `test: ${this.counter}`;
    this.counter++;
  }
}

To catch changes from the template in the template's component, use a setter instead:

  // To catch changes from the template
  _test: string;
  get test(): string {
    return this._test;
  }

  @Input()
  set test(value: string) {
    this._test = value;
    console.log("Textbox value changed: " + this._test);
  }

Or you can use Sajeetharan's suggestion to catch the template's change in its associated template. It will also work.

DeborahK
  • 57,520
  • 12
  • 104
  • 129
5

What you need here is ngModelChange not ngOnChanges

<input type="text" placeholder="Test field" (ngModelChange)="printVal()">

and then

printVal(){
  //detect model change here
}

ngOnChanges works over @input event emitter

Sajeetharan
  • 216,225
  • 63
  • 350
  • 396
  • can you please help me to fix this issue https://stackoverflow.com/questions/50166996/ngonchanges-not-get-triggered-in-angular4 – Nikson May 04 '18 at 04:11