Search code examples
angularangular2-changedetection

How to update changes in child component


Child component's @input value not updating its value in html, as two-way binding usually does. Here is my code.

parent.component.html

<app-child [i]="selectedMonth" (monthChanged)="monthChanged($event)"></app-child>

monthChanged(d: Date) {
    this.selectedMonth = d; // this is working as expected.
    console.error(this.selectedMonth); // working...
  }

child.component.html

<div>
    <span (click)="addMonth(-1)">Prev </span>
    <span>{{i | date:'MMM-yyyy'}}</span> // this value not being changed.
    <span (click)="addMonth(1)">Next </span>
</div>

child.component.ts

export class ChildComponent implements OnInit {
  @Input() i: Date;
  @Output() monthChanged = new EventEmitter<Date>();

  constructor() { }

  ngOnInit(): void {
  }

  addMonth = (m: number) => {
    this.i.setMonth(this.i.getMonth() + m);
    this.monthChanged.emit(this.i);
  }

}

What I tried?

this.changeDetectorRef.detectChanges();

ngOnChanges(changes: SimpleChanges) {
    console.error(this.i); // no error log...
    this.i = changes.i.currentValue;
    console.error(this.i); // no error log...
  }

But none working. What else should I use?


Solution

  • I've created a stackblitz reproducing your problem. You can check it here

    You can check console logs. When you update within child component with this.i.setMonth(this.i.getMonth() + m) it also updates parents selectedMonth. Because they are the same object. Since, the object reference does not change, Angular won't run change detection. You can fix this by creating new object within monthChanged as follows

    Change

    monthChanged(d: Date) {
      this.selectedMonth = d; 
      ...
    }
    

    to

    monthChanged(d: Date) {
      this.selectedMonth = new Date(d); 
      ...
    }