Tanzeel
Tanzeel

Reputation: 4998

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

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.

Upvotes: 3

Views: 5882

Answers (2)

ayala
ayala

Reputation: 365

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

  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;
  }

  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
    }
 
  }
}

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

Upvotes: 6

Drenai
Drenai

Reputation: 12367

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

Upvotes: 1

Related Questions