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!
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With