Home > other >  How to re-render a child component when new data arrives from the parent
How to re-render a child component when new data arrives from the parent

Time:07-05

I've following code. Parent is sending some data to the child component using @Input directive:

Parent HTML

<div>
  <my-timeline
   [data]="data">
  </my-timeline>
</div>

In Parent TS there is a service that provides data to data

Parent TS

data=[];
...
this.service.getData().subscribe(res => {
  res.map(item=>{
    this.data.push({
      ...
     });
   })
})

And the child is receiving it as

Child TS

@Input data;
eventArray=[];

ngOnInit() {
  console.log("called"); // called only for the first time
  createTimeline(data[0].id); // called only for the first time
}

createTimeline(id) { // called only for the first time
  this.eventArray.push(.....)
}

Child HTML

<p-timeline [value]="eventArray">
...
</p-timeline>

The problem is that the p-timeline continues to show old events i.e. the events it loaded for the very first time. Because with subsequent data change from the Parent it is not causing ngOnIt in child to run. That is why createTimeline was never called again. Please pitch in.

CodePudding user response:

In order to detect changes to an @Input property you can implement one of the following:

  1. OnChanges lifecycle hook -

    First, lets explain what is OnChanges hook?

    From Angular.io:

    OnChanges is a lifecycle hook that is called when any data-bound property of a directive changes. Define an ngOnChanges() method to handle the changes.

Lets implement the OnChanges lifecycle hook, something like this:

@Component({...})
export class SelectedPlayerComponent implements OnChanges {
  @Input() data;

  ngOnChanges(changes: SimpleChanges) {
    if(changes.data)
    {
       this.createTimeline(changes.data.currentValue[0].id);//the new value that's changed
    }
 
  }
}
  1. Setter - Implement the @Input() property as getter and setter, something like this:

 private _data: any;

  @Input()
  set data(value: any) {
    this._data= value;
   if(this._data)
     this.createTimeline(this._data[0].id)
  }

  get data(): any{
    return this._data;
  }

Thanks for Todd Motto good article about detect input changes in angular

CodePudding user response:

Use ChangeDetectionStrategy.Default on all your components or use immutable data approach e.g

this.data = [...this.data, {//item}];

Can read up on it in the docs, along with how Angular ngOnInit works

  • Related