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!
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.