Aymen Kanzari
Aymen Kanzari

Reputation: 2013

ngOnChanges not trigger when setting property directly

I used the modal from ng-bootstrap

In my parent component i used modalService to open the modal, and i sent data to the modal using componentInstance.

In the modal component i used ngOnChanges to get the data that i sent. but the ngOnChanges is not trigged.

stackblitz

parent component

  public toAttach(): void {
    let modalRef = this.modalService.open(HelloComponent);
    modalRef.componentInstance.attachments = this.attachments;
  }

modal component

  ngOnChanges(changes: SimpleChanges) {
    console.log("start!");
    if (changes["attachments"] && changes["attachments"].currentValue) {
      console.log(changes["attachments"].currentValue);
    }
  }

Upvotes: 1

Views: 2222

Answers (3)

buchipper
buchipper

Reputation: 654

When you set the component instance's values directly, it will not trigger an ngOnChanges. ngOnChanges is triggered when the value binding for a component changes. It also depends on the change detection strategy. If you want to change the value for a component instance variable directly, you can use a setter method in which you could do what you want to do in ngOnChanges. For example -

import {
  Component,
  Input,
  AfterViewInit,
  ChangeDetectorRef,
  SimpleChanges,
  OnChanges
} from "@angular/core";

@Component({
  selector: "hello",
  templateUrl: "./hello.component.html"
})
export class HelloComponent implements AfterViewInit, OnChanges {
  @Input()
  public attachments: any[];

  constructor(private cd: ChangeDetectorRef) {}

  ngAfterViewInit() {
    this.cd.detectChanges();
  }

  setAttachments(attachments: []) {
     this.attachments = attachments.slice();
     // => DO YOUR WORK HERE
     // Like calling change detection.
   }

  ngOnChanges(changes: SimpleChanges) {
    console.log("start!");
    if (changes["attachments"] && changes["attachments"].currentValue) {
      console.log(changes["attachments"].currentValue);
    }
  }
}

And in the parent component, call

public toAttach(): void {
    let modalRef = this.modalService.open(HelloComponent);
    modalRef.componentInstance.setAttachments(this.attachments);
  }

Upvotes: 5

hanan
hanan

Reputation: 1880

Seems like by setting property directly angular does not fire ngOnChange

in ngOnInit() this.attachments are populated

  ngOnInit() {
 console.log(this.attachments);
}

you can use them there

enter image description here

if u still want to use ngOnChanges for regular use then in this case use one input for regular usage and one only setter for this purpose in setter u will call on ngOnChange. yep this is a workaround but it will work!!

Upvotes: 1

Slawa Eremin
Slawa Eremin

Reputation: 5415

You can use BehaviorSubject in parent something like this:

export class AppComponent {
  private attachmentsSubject: any = new BehaviorSubject([{
      idChild: "111111111",
      startDate: "2020-06-29T23:00:00.000+0000",
      endDate: "2020-07-21T23:00:00.000+0000",
      motif: "Déménagement"
  }]) ;

  constructor(private modalService: NgbModal) {}

  public toAttach(): void {
    let modalRef = this.modalService.open(HelloComponent);
    modalRef.componentInstance.attachmentsSubject = this.attachmentsSubject;
  }
}

so child component will be simpler:

export class HelloComponent {
  attachmentsSubject: any;
}

<div class="modal-body">
  <div *ngFor="let item of (attachmentsSubject | async)">
    {{ item.idChild}}
  </div>
</div>

It works because in parent component you set the actual data through componentInstance.

I have updated your code: https://stackblitz.com/edit/angular-ivy-rmnvsf?file=src%2Fapp%2Fhello.component.html

Upvotes: 0

Related Questions