Search code examples
asynchronousvue.jsaxiosvuex

Vuex: Computed Property Returns Undefined - asyc Axios


I have async axios calls to my DB that I am dispatching with an action when the site loads. (I've tried dispatching in beforeEnter() on my Vue-router, beforeCreated(), and Created() on my Form.Vue)

I have a computed property return the info using a getter.

The problem I am experiencing is the data is getting there after the page has finished loading and returns Undefined - nothing renders on the page.

If I check my Vue DevTools, all the data is in the correct places in the State.

How can I get the data to finish loading before the page?

//ACTIONS

async loadInputs({ state, getters, commit, dispatch }) {    
 if (!state.loading) {
  commit('setLoading', true)

  const inputLists = axios.get('/companyInputLists')
  const inputs = axios.get('/companyInputs')

  commit('setLoading', false)
  commit('loadInputs' , [await inputLists, await inputs])

 }
},

set ({commit}, value) {
  commit('updateValue', value)
},

//MUTATORS

setLoading(state, value) {
  state.loading = value
},

 loadInputs(state, data){
  state.layout = {}
  state.data = {}
  data[0].data.map(list => {
    list['inputs'] = []
    state.layout[list.order] = list

    data[1].data.map(input => {
        if(input.list_id == list.id){
            state.layout[list.order].inputs.push(input)
            state.data[input.label] = ''
        }
     })
   })
 },

updateValue(state, value) {
  state.data[value.type] = value.value
},

//GETTERS

get(state) {
    console.log(state)
    return state
 },
}

//FORM.VUE

  <span>

    //LIST TEST and v-if test
    <div v-if="lists">
      {{lists}}
    </div>
    test
    {{ lists }}



<v-layout row wrap justify-center>

  <draggable class="dragArea layout row wrap justify-center" :options="{group:'lists'}">
    <v-flex v-for="list in lists" v-bind:key="list.index" :class="[list.label, flexBoxSize(list.size)]">

      <v-subheader v-text="list.label"></v-subheader>

      <draggable class="dragArea layout row wrap" :options="{group:'inputs'}">
        <v-flex v-for="item in list.inputs" v-bind:key="item.index" :class="[item.label, flexBoxSize(item.size)]">

          <textfield v-if="item.type_id == 1" formType="clientForm" :label="item.label" :required="item.required"></textfield>
          <email v-if="item.type_id == 2" formType="clientForm" :label="item.label"  :required="item.required"></email>
          <phone v-if="item.type_id == 3" formType="clientForm" :label="item.label"  :required="item.required"></phone>
          <calendar v-if="item.type_id == 4" formType="clientForm" :label="item.label"  :required="item.required"></calendar>
          <googleMap v-if="item.type_id == 5" formType="clientForm" :label="item.label"  :required="item.required"></googleMap>
          <autocomplete v-if="item.type_id == 6" formType="clientForm" :label="item.label"  :required="item.required"></autocomplete>


        </v-flex>
      </draggable>

    </v-flex>
  </draggable>


  <v-layout row wrap justify-center>
    <submitButton formType="clientForm" path="/clientForm" :references="this.$refs"></submitButton>
    <clearButton formType="clientForm" :references="this.$refs"></clearButton>
  </v-layout>

  </v-layout>
 </span>
</template>

<script>
export default {
  components: {
    draggable,
  },

  beforeCreate(){
    this.$store.dispatch('clientForm/loadInputs')
  },

  computed: {
    lists: {
      get() {
        return this.$store.getters['clientForm/get'].layout
      },
      set(value) {
        this.$store.commit('clientForm/updateInputList', value)
      }
    }
  },

Vuex Dev Tools Showing Data in State After Page Loads


Solution

  • I figured out the answer over the winter holidays last year and realized there never was a definitive conclusion posted here. After much trial and error and reading through documentation I came across the answer in the Vue.js documentation.

    https://v2.vuejs.org/v2/api/#Vue-set

    Vue.set(target, key, value) Adds a property to a reactive object, ensuring the new property is also reactive, so triggers view updates. This must be used to add new properties to reactive objects, as Vue cannot detect normal property additions (e.g. this.myObject.newProperty = 'hi').

    Using this function, I was able to load my data via an axios call and have Vue detect the changes and update the DOM.

    Also you may want to take note of Vue.delete for removing data with reactivity.