I've been building a web-app using Vue 2.0 and single file components and ran across an issue that I can't figure out and need to solve.

As it currently stands, my relevant file structure is as follows...

main.js

/*
 * main.js
 *
 * Initial entry point for all Vue and component code
 */

import Vue from 'vue'
import VueResource from 'vue-resource'
import App from './App.vue'
import './sockets.js'

Vue.use(VueResource)

new Vue({
  el: '#app',
  render: element => element(App)
})

sockets.js

import App from './App.vue'

const socket = io('http://localhost:8181')

socket.on('test', payload => App.$set('test', payload))

/*socket.on('lot_change', payload => {
  console.log(payload)
  //Logic to find differences and reset
})*/

App.vue

<template>
  <div id="app">
    {{ test }}
    <template v-for="lot in allLots">
      <lot
        :uuid="lot.uuid"
        :closed="lot.closed"
        :controllerId="lot.controllerId"
        :institution="lot.institution"
        :number="lot.lotNumber"
        :permits="lot.permits"
        :taken-spaces="lot.takenSpaces"
        :total-spaces="lot.totalSpaces"></lot>
    </template>
  </div>
</template>

<script>
import Lot from './components/Lot.vue'

export default {
  data() {
    return {
      allLots: [],
      test: {}
    }
  },

  components: {
    Lot
  },

  created() {
    this.$http.get('/all').then(res => JSON.parse(res.body)).then(data => {
      this.allLots = data.results
    })
  }
}
</script>

<style>
html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}
</style>

On a new connection, my express app emits a 'test' event to the socket which is received by the client socket perfectly fine, however, what I want to do is that the payload from the back-end socket's emission and assign it to the data of the App component.

In the callback for the socket.on('test'), I am currently getting an undefined function type of error for the App.$set. I have also tried the global API using Vue.set(App, 'test', payload) which also didn't work.

Any help would be greatly appreciated!

EDIT

In other words, how can I manipulate the data object of a single file component from another JS file after importing it?

Try using Vuex

It looks like you should consider using Vuex for this and it would be quite easy to setup even though it seems long.

This would be a basic example of the Vuex store file:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    allLots: []
  },
  getters: {
    lots: state => {
      return state.allLots
    }
  },
  mutations: {
    setAllLots (state, lots) {
      state.allLots = lots
    }
  },
  actions: {
    setAllLots ({ commit }, lots) {
      commit('setAllLots', lots)
    }
  }
})

In your main.js file:

import store as './your-path/store'

and update below:

new Vue({
  el: '#app',
  store,
  render: element => element(App)
})

This sets up vuex with your vue instance. Now you will have to update the allLots data in vuex by calling the store's dispatch function in your request to get lots in App.vue...

Import store into App.vue similar to what you did in main.js and update this code:

created() {
    this.$http.get('/all').then(res => JSON.parse(res.body)).then(data => {
      store.dispatch('setAllLots', data.results)
    })
  }

So what this will do is send data.results as the lots parameter in your store's action: setAllLots

...which commits the lots parameter to your store's mutation: setAllLots

...which updates your allLots data with the lots parameter

Now that vuex is updated, you can retrieve this information anywhere your store is imported using the lots getter.

So to get it in your App.vue, use a computed property (replaces allLots in your returned data) like this:

computed: {
  allLots () {
    return store.getters.lots
  }
}

Your allLots will be rendered in your template from the computed property now.

My first response to this was incorrect, because I originally misread your issue, but realized this should still work.

Try to once again import store and call:

socket.on('test', payload => store.dispatch('setAllLots', payload))

Assuming your socket code is correct, this should work for you since the vuex is set and your computed property is reactive. I did not test this last part, so I hope this helps you out!

Regardless, I hope this helps you or anyone with quickly setting up Vuex.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.