user3340927
user3340927

Reputation: 27

Angular: change detection triggers only once when changing value immediately in parent component

I am setting a value from the parent component and changing it immediately. In the child component, change detection executes only once.

Stackblitz code base

Parent's code: HTML

<h1>Parent Component</h1>
<p>Contents of the parent component</p>
<button (click)='parentClickEvt()'>Parent Button</button>
<child [message]="msg" (informParent)="parentWillTakeAction($event)"></child>

Parent's code: TS

export class ParentComponent {

  msg: string="testing";

  parentWillTakeAction(message) {
    this.messageFromChild = message;
  }

  parentClickEvt() {
    this.msg = "Message from parent to child";
    this.msg = "India";
    this.msg = "India, ASIA";
    this.msg = "JAPAN";
    this.msg = "JAPAN, ASIA";
  }
}

Child's code: TS

export class ChildComponent implements OnInit {

  @Input() message: string;
  @Output() informParent = new EventEmitter();

  ngOnChanges(simpleChanges: SimpleChanges) {
    console.log(simpleChanges.message.currentValue)
  }
}

Executing parentClickEvt method from parent is changing msg value 4 times. In child component, ngOnChanges is supposed to execute 4 times. But it is only executing once with the latest value.

Please suggest how ngOnChanges should execute according to all changes

Upvotes: 0

Views: 76

Answers (1)

v-pat
v-pat

Reputation: 74

First implement OnChanges on child component.

Change detection is not working because you are changing value of msg without letting previous change detection to be completed.

I would suggest to change the approach of this rapid reassignment of values if possible, However I have a workaround. see if you can use it.

import { Component, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  messageFromChild: string = '';
  msg: string = 'testing';

  constructor(private changeDetectorRef: ChangeDetectorRef) {}

  parentWillTakeAction(message: any) {
    this.messageFromChild = message;
  }

  async parentClickEvt() {
    this.msg = 'Message from parent to child';
    await this.detectChanges();
    this.msg = 'India';
    await this.detectChanges();
    this.msg = 'India, ASIA';
    await this.detectChanges();
    this.msg = 'JAPAN';
    await this.detectChanges();
    this.msg = 'JAPAN, ASIA';
  }

  detectChanges(): Promise<void> {
    return new Promise((resolve) => {
      this.changeDetectorRef.detectChanges();
      resolve();
    });
  }
}

By this way you will be able to catch change in ngOnChanges of child component.

Upvotes: 0

Related Questions