Angular - Input data not immediately available on child component, why?

1.9k views Asked by At

I have a child Calendar Component that receives events from his father through an input field.

@Input() private events: any[];

When the month changes the parent gets new events from an API Service and calls the child component to show them.

private populateEventsForCurrentMonth() {
return this.calendarService.getEventsAsAdmin(this.getCurrentStartDate(), 
this.getCurrentEndDate())
.then((evts) => {
  this.events = evts;
  this.calendarChild.selectEventDaysIfApplies();
})
.catch((err) => {
  console.log('error getting events', err);
});

}

But when the child tries to access the events they haven't been updated!

My workaround was wrapping the child function in a timeout of 0 milliseconds to put the entire execution at the end of the event loop.

public selectEventDaysIfApplies() {
setTimeout(() => {
  if (this.events) {
    this.events.forEach((event) => {
      let eventDate = new Date(event.starts_at);
      if (this.datesBelongToSameMonth(eventDate, this.currentDate)) {
        let dayWithEvent = this.days.find( (day) => {
          return day.number == eventDate.getDate();
        });
        if (!dayWithEvent.selected) {
          dayWithEvent.hasEvent = true;
        }
      }
    });
  }
}, 0);

}

Is there a better way of doing it? Maybe an Angular best practice that I should be implementing?

Thanks!

1

There are 1 answers

1
Kim Kern On BEST ANSWER

The data is not available yet, because this function is handled synchronously:

this.events = evts;
this.calendarChild.selectEventDaysIfApplies();

Immediately, after this.events has been set, the child components runs its method selectEventDaysIfApplies(). That is before the Angular change detection is run.

In my opinion, the parent component should not know about any checks and modifications its child components have to do.

A better solution would be to use the lifecycle hook OnChanges, which is triggered whenever an input of the component changes.

ngOnChanges(changes: SimpleChanges) {
  this.selectEventDaysIfApplies();
}

If your component has more than one input, you can check which one was changed.

Read more about this in the docs.