Pekehata
Pekehata

Reputation: 29

Fetching data from firebase before mounted() on Vue

I am trying to fetch data from firebase before mounted() hook is called, but firebase query is asynchronous function and I'm struggling to handle those. Here is my code snippet:

<template>
  <b-table-simple sticky-header="90%" class="table-bordered">
    <b-thead head-variant="dark">
      <b-tr>
        <b-th >氏名</b-th>
        <b-th v-for="date in printables" :key="date" class="text-center" v-html="date"></b-th>
      </b-tr>
    </b-thead>
    <b-tbody v-if="fetched">
      <template v-for="(staff_data, staff_id) in project.assigned_staff">
        <b-tr :key="staff_id">
          <b-th rowspan="6">
            <b-tr>
              <b-th rowspan="6" v-html="staff_data.name.split(/ | /).join('<br>')"></b-th>
              <b-th >[]</b-th>
            </b-tr>
            <b-tr>
              <b-th >出勤</b-th>
            </b-tr>
            <b-tr>
              <b-th >残業</b-th>
            </b-tr>
            <b-tr>
              <b-th >深夜</b-th>
            </b-tr>
            <b-tr>
              <b-th >内容</b-th>
            </b-tr>
            <b-tr>
              <b-th >弁当</b-th>
            </b-tr>
          </b-th>
          <b-td v-for="i in days.length" :key="i">
            <b-form-checkbox @change.native="setBGColor($event)" :ref="`select-${i}`"></b-form-checkbox>
          </b-td>
        </b-tr>
        <b-tr :key="staff_id">
          <b-td v-for="day in days" :key="day">
            <b-form-select @change.native="setBGColor($event)" :ref="`regular-${staff_id}-${day}`" :options="regularTimeOption"></b-form-select>
          </b-td>
        </b-tr>
        <b-tr :key="staff_id">
          <b-td v-for="day in days" :key="day">
            <b-form-select @change.native="setBGColor($event)" :ref="`overtime-${staff_id}-${day}`" :options="overTimeAndLateNightOption"></b-form-select>
          </b-td>
        </b-tr>
        <b-tr :key="staff_id">
          <b-td v-for="day in days" :key="day">
            <b-form-select @change.native="setBGColor($event)" :ref="`latenight-${staff_id}-${day}`" :options="overTimeAndLateNightOption"></b-form-select>
          </b-td>
        </b-tr>
        <b-tr :key="staff_id">
          <b-td v-for="day in days" :key="day">
            <b-form-select @change.native="setBGColor($event)" :ref="`type-${staff_id}-${day}`" :options="typeOption"></b-form-select>
          </b-td>
        </b-tr>
        <b-tr :key="staff_id">
          <b-td v-for="day in days" :key="day">
            <b-form-select @change.native="setBGColor($event)" :ref="`bento-${staff_id}-${day}`" :options="bentoOption"></b-form-select>
          </b-td>
        </b-tr>
      </template>
    </b-tbody>
  </b-table-simple>
<template>
//... 

const project

export default {
 beforeCreate() {
  // fetching "project" which is necessary to determine table structure (laying out <b-tr>, <b-th> and <b-td>)
  // this should be done before "mounted()" hook
  firebase.database().ref(`/project/${projectId}`)
                     .once('value')
                     .then(...)
  // fetching "daily_report" which is data to fill each <b-td>
  // this should be executed after "project" is fetched
  firebase.database().ref(`/daily_report/${projectId}`)
                     .once('value')
                     .then(snapShot => {
                       project = snapShot.val()                 
                       ...
                     })
 },
 mounted() {
   const elRegular = this.$refs[`regular-${postfix}`]
   elRegular.value = report.hours_regular
 },
 //...
}

Desireble order for me is:

But because firebase.database().on() and once() are asynchronous functions, actual order will be:

The biggest problem here I think is fetching project completed after mounted() initiated. I searched about async/await and beforeRouteEnter guard of vue router, but none of them seems to solve my problem. How can I get promise-based functions done before mounted hook initiated?

Upvotes: 0

Views: 486

Answers (1)

Paul-Louis Mas
Paul-Louis Mas

Reputation: 429

Instead of using an external variable, you should add it to the data section of you component. This way, Vue can use it after the async call to Firebase.

export default {
 data() {
  project: {
   // An empty array so Vue start with no lines,
   // and add them once the array is populated.
   assigned_staff: []
 },
 beforeCreate() {
  // fetching "project" which is necessary to determine table structure
  // (laying out <b-tr>, <b-th> and <b-td>)
  // this should be done before "mounted()" hook
  firebase.database().ref(`/project/${projectId}`)
                     .once('value')
                     .then(...)
  // fetching "daily_report" which is data to fill each <b-td>
  // this should be executed after "project" is fetched
  firebase.database().ref(`/daily_report/${projectId}`)
                     .once('value')
                     .then(snapShot => {

                       // Set the property 'project' of the commponent
                       // to the value of the snapshot
                       this.$set(this, 'project', snapShot.val());

                       ...
                     })
 },
 mounted() {
   const elRegular = this.$refs[`regular-${postfix}`]
   elRegular.value = report.hours_regular
 },
 ...
}

Upvotes: 1

Related Questions