Nikhil Nanjappa
Nikhil Nanjappa

Reputation: 6642

OnChanges doesnt fire if @Input is an object & one of its property updates

What I'm trying to do ?

I have a parent component(say parent) which contains 2 children components(say child-1 and child-2). When one of the DOM element value within child 1 changes, I'm assigning the new value to one of the properties of an object and emitting the object to parent. Parent then assigns the incoming object to its own local object, which I'm passing as an input([setupValues]) to child 2 component. Within Child 2, when there is any change to that @Input object, I want to assign one of its properties to a local variable(which is not happening because the child 2 Onchanges doesn't get fired even when one of the properties within @Input object has changed).

My Source Code(most removed due to brevity)

Consider I have an interface ISetups.ts

export interface ISetups {
  DOB: string;
  DOD: string;
  DOE: string;
}

Markup of parent.html goes as follows

<child-1 [input]="someVariable" (setupsChanged)="onSetupsChange($event)">
</child-1>

{{ allSetups.DOB }} <!-- the change is shown correctly here -->

<child-2 [setupValues]="allSetups"></child-2>

In parent.ts

export class ParentComponent {

  someVariable: string;
  allSetups: ISetups;

  onSetupsChange(allSetups: ISetups) {
    // emitted object from child 1 is assigned to local object
    this.allSetups = allSetups;
  }
}

In child-1.html

<input class="form-control" [(ngModel)]="ownDOB" (blur)="emitChange()" >

In child-1.ts

export class Child1Component {

  @Input() input: string;
  @Output() setupsChanged: EventEmitter<ISetups> = new EventEmitter<ISetups>();
  allSetups: ISetups;
  ownDOB: string;

  emitChange() {
    this.allSetups.DOB = this.ownDOB;
    this.setupsChanged.emit(this.allSetups); //emitting object to parent
  }
}

In child-2.html

<p>{{ localDOB }}</p>

In child-2.ts

export class Child2Component implements OnChanges {

  localDOB: string;
  @Input() setupValues: ISetups;

  ngOnChanges(): void {
    console.log("this does not fire if setupValues.DOB changes");
    this.localDOB = this.setupValues.DOB;
  }

}

What worked ?

Passing the property directly as another input worked

<child-2 [DOB]="allSetups.DOB" [setupValues]="allSetups"></child-2>

The above works but obviously its not a nice way & I don't want to do this.

The above proves that when I send the variable on its own, it fires the OnChanges but doesn't fire when just one of the properties within an object is changed.

Any help is much appreciated.

Upvotes: 0

Views: 232

Answers (1)

Reza
Reza

Reputation: 19863

this is happened because your reference to object is not changed, so if in your parent.ts change your code to this, it should work. By this way (using spread operator) you are creating a new instance of object

onSetupsChange(allSetups: ISetups) {
    // emitted object from child 1 is assigned to local object
    this.allSetups = {...allSetups};
  }

Upvotes: 1

Related Questions