2

I am trying to learn Angular 2 by experimenting and I found that ngOnChanges doesn't fire in the following code:

app.component.ts:

import { Component, Input } from "@angular/core"
import { FormsModule } from '@angular/forms';
import { OnChanges, SimpleChanges } from '@angular/core/src/metadata/lifecycle_hooks';
@Component({
  selector: 'my-app',
  template: `
    Enter text : <input type="text" [(ngModel)]='userText'  />
    <br/>
    Entered text :  {{userText}} 
  `
})

export class AppComponent {
  @Input()  userText: string;
  name: string = "Tom";

  ngOnChanges(changes: SimpleChanges): void {
    for (let propertyName in changes) {
      let change = changes[propertyName];
      let current = JSON.stringify(change.currentValue);
      let previouis = JSON.stringify(change.previousValue);
      console.log(propertyName + ' ' + current + ' ' + previouis);
    }

  }
}

The above code doesn't fire ngOnChanges

However, if I create a separate component "simple" and use it in app.scomponent.ts, the following works:

app.component.ts:

import {Component} from "@angular/core"
import {FormsModule} from '@angular/forms'; 
@Component({
  selector: 'my-app',
  template: `
    Enter text : <input type="text" [(ngModel)]='userText' />
    <br/>
    <simple [simpleInput]='userText'></simple>
  `
})

export class AppComponent{
  userText:string;
  name:string ="Tom";


}

simple.component.ts:

import {Component,Input} from '@angular/core';
import { OnChanges,SimpleChanges } from '@angular/core/src/metadata/lifecycle_hooks';

@Component({
    selector:'simple',
    template: `You entered {{simpleInput}} `
})
export class SimpleComponent implements OnChanges{
    ngOnChanges(changes: SimpleChanges): void {
        for(let propertyName in changes){
            let change=changes[propertyName];
            let current=JSON.stringify(change.currentValue);
            let previouis=JSON.stringify(change.previousValue);
            console.log(propertyName+ ' '+current+ ' ' +previouis);
        }

    }
    @Input() simpleInput: string;

}

Can someone please provide an explanation? What am I doing wrong here?

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
SamuraiJack
  • 5,131
  • 15
  • 89
  • 195
  • https://angular.io/guide/lifecycle-hooks#onchanges `Angular calls its ngOnChanges() method whenever it detects changes to input properties` – Jota.Toledo Apr 08 '18 at 08:51
  • @Jota.Toledo if Angular calls its ngOnChanges() method whenever it detects changes to input properties then why is it not calling it when `userText` is an input property and being changed? – SamuraiJack Apr 08 '18 at 08:57
  • Because the change needs to be pushed by the container of the component. In your 2nd scenario you have appcomponent pushing data into simplecomponent through the input property. In the 1st scenario this isnt the case, as appcomponent is your root component, meaning that its not container by other. – Jota.Toledo Apr 08 '18 at 09:01
  • You cannot provide inputs to a bootstrapped component, such as AppComponent. More info at https://stackoverflow.com/questions/42412603/angular-input-is-not-working-with-bootstrap-component – user184994 Apr 08 '18 at 09:02
  • You can indeed, but is meaningless. – Jota.Toledo Apr 08 '18 at 09:04
  • @Jota.Toledo does that mean that if I want to log previous and current values of the textbox. I HAVE TO create a separate component such as `simple component ` in this case and then pass the values from app.component to simple component? Isn't that unproductive? – SamuraiJack Apr 08 '18 at 09:43
  • 1
    You dont *have to*, is an option yeah, but there are others: rxjs+immutability or use the (ngModelChange) event to log the change. If you want to use the `SimpleChanges` API for logging purposes, you are indeed obligated to use input properties. – Jota.Toledo Apr 08 '18 at 09:48

1 Answers1

0

I think you might misunderstand the intention of @Input fields. @Input fields allow to communicate between parent and child components, they are not needed for databindung within a component. No attribute is needed for databindung, the fields just have to be public. As a Lifecycle Hook ngOnChanges is intended to react to changes on @Input fields, not html input elements.

If you want more elaborate change behaviour than two-way-databinding try

<input type="text" [(ngModel)]='userText' (ngModelChange)="onUserTextChange($event)">

(I am sorry if the above code doesn't work out of the box, I will test and clean it as soon as I am back at my developer machine)

You can finde more information here.

Jörg Reichardt
  • 361
  • 5
  • 14