Pass data from nested child component to parent

I have a parent component (CalendarViewModel) that has a child component (CalendarWeek) that has another child component (CalendarDay). I’m trying to update the currentDay property in the parent component that gets passed to both child components. The trigger happens from the nested child component CalendarDay. I managed to do this by using .call and @bindable, but I wonder if there is a better way to do this?

This is my code (I left all irrelevant out):

// Parent
export class CalendarViewModel {
    currentDay: CalendarDay;
    weeks: Array<number>;

    constructor() {
        this.weeks = [0, 1, 2, 3, 4];
    }

    setCurrentDay(day: Date) {
        this.currentDay = day;
    }
}

// Parent template
<template>
  <require from="./calendarWeek"></require>

  <div class="week">
    <div repeat.for="week of weeks">
      <calendar-week current-day.bind="currentDay" set-current-day.call="setCurrentDay($event.day)"></calendar-week> 
    </div>
  </div>
</template>


// Child
export class CalendarWeek {
    days: Array<number>;
    @bindable @observable currentDay: CalendarDay;
    @bindable setCurrentDay;

    constructor() {
        this.days = [0, 1, 2, 3, 4, 5, 6];
    }

    setCurrentDayInWeek(day) {
        this.setCurrentDay({day: day});
    }
}

// Child template
<template>
  <require from="./calendarDay"></require>

  <div class="align-horizontally-grid">
    <div class="align-horizontally" repeat.for="day of days">
      <calendar-day current-day.bind="currentDay" set-current-day-in-week.call="setCurrentDayInWeek($event.day)"></calendar-day>
    </div>
  </div>
</template>



// Nested child
export class CalendarDay {
    date: Date;
    @bindable @observable currentDay: CalendarDay;
    @bindable setCurrentDayInWeek;

    changeCurrentDayToThis() {
        this.setCurrentDayInWeek({day: this});
    }
}

// Nested child template
<template>
  <button click.trigger='changeCurrentDayToThis()'>Change day</button>
</template>

Yes, dispatch a CustomEvent in a child and add an event handler in parent

1 Like

As an alternative, you could inject the CalendarViewModel into CalendarWeek and CalendarWeek into CalendarDay

@inject(CalendarWeek)
export class CalendarDay{
   date: Date;
   constructor(public calWeekRef: CalendarWeek){}

   dayChange(){
       // work directly on calendar-weeks viewmodel here
        this.calWeekRef.dayChange(this.date);
   }
}


@inject(CalendarViewModel)
export class CalendarWeek{
   constructor(public calViewModel: CalendarViewModel){}

   dayChange(date: Date){
       // work directly on calendar viewmodel here
        this.calViewModel.dayChange(this.date);
   }
}