1

I am new to ngOnchanges and facing below issue.

my parent component is setting recom value on ngOnChanges and sends the same value to child component. child receives the same as input in ngOnChanges. depending on some condition like totalVal>0 i set inputField to true which is initially set to false. if inputField is true i show some component in reactive forms. but when my below structure execute model2Form() it still gets inputField as false. I cant post actual code so just created a structure as per my project as shown below.

Please suggest how do i solve this issue.

// parent component

ngOnchanges(){
  this.recom = [{
    totalVal: 5000,
    monthlydata: true
  }]
}

//child component

@Input()
private recom: any;

inputField: boolean = false;


ngOnChanges(){
  this.setValue();
  this.loadFuture();
}

setValue(){
  if(this.recom.totalVal > 0){
    this.inputField = true;
  }
}

loadFuture(){

}

model2Form(){

//getting input field as false even if i set it as true in setValue()

  if(inputField){
    this.heroForm.setControl('secretLairs', addressFormArray);
  }

}

<!-- parent component>

<parent-comp [recom]="recom"></parent-comp>


<!-- child component -->

<div [FormControlName]="secretLairs"> </div>
zgue
  • 3,793
  • 9
  • 34
  • 39
Jay
  • 375
  • 2
  • 5
  • 17

2 Answers2

11

The problem is that you are trying to monitor changes on an Array. Arrays and Objects don't work so well with ngOnChanges because they are passed by reference, not value. Strings and Integers work well here because its easy for Angular to tell when the value has been changed. Since Javascript passes Objects and Arrays by reference, Angular will only trigger change detection when the reference changes.

Three ways to solve this really:

  1. Store your complex value in a service as either a subject or BehaviorSubject if you have access to your values right away. Then subscribe to it throughout your application where needed. Every time a new value is pushed to the Observable, your components will run their logic on it.
  2. Separate the properties you need to monitor into separate @Inputs() that are monitoring the value of something like a string or number.
  3. The third way to solve this is to assign the Object/Array to an entirely new entity using Object.assign() function and replacing the value of your property outright with the new entity thus creating a new reference.
joshrathke
  • 7,564
  • 7
  • 23
  • 38
0

change event ngOnchange only occur when there is any change done to your input property of component. So in your case parentcomponent has no input property and so ngOnchange does not fire for you.

I created code for you which is working - in below code i used parentcomponent in my appcomponent.ts and when I loaded, ngOnchange does not work, but child ngOnchange works and its input property gets changed.

So I changed child property in OnChange event of textbox control and when i changed value in my textbox control, then child control ngOnchange got triggered and updated value came.

If you pass input value to parent control and make change in that than you parent and child ngOnchange will work.

Parent component


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

@Component({
    selector: 'parentcomp',
    template: `
    this needs to be wok 
  <h3>Countdown to Liftoff (via local variable)</h3>
  <input type="text" [ngModel] = "display"  (ngModelChange)="onChange($event)"/>
  {{display}}
  <Childcomp [recom] = "recom"> </Childcomp>
  `
})
export class ParentComponent implements OnChanges, OnInit {
    ngOnInit(): void {
        this.recom = [{
            totalVal: 5000,
            monthlydata: false
        }];
    }
    display: string;
    recom: any;

    constructor() {
        this.display = "test";
    }

    onChange()
    {
        this.recom = [{
            totalVal: 5000,
            monthlydata: true
        }];

    }

    //this will not trigger 
    ngOnChanges(changes: SimpleChanges): void {
        debugger;
        this.recom = [{
            totalVal: 5000,
            monthlydata: true
        }];
    }
}

Child Component


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

@Component({
    selector: 'Childcomp',
    template: `
  <h3>Child component</h3>

  `
})
export class Childcomponent implements OnChanges {
    @Input()
    private recom: any;

    constructor() {
    }

    ngOnChanges(changes: SimpleChanges): void {
       debugger;
       for (let propName in changes) {
        let chng = changes[propName];
        let cur:any  = chng.currentValue;
        let prev:any = chng.previousValue;
        alert(`${propName}: currentValue = ${cur[0].monthlydata}, previousValue = ${prev[0].monthlydata}`);
      }
    }
}
Spikolynn
  • 4,067
  • 2
  • 37
  • 44
Pranay Rana
  • 175,020
  • 35
  • 237
  • 263