3
votes

I am wondering what the cleanest way to expose data properties on a single-file Vue component without polluting the global namespace is.

In my main entry file(app.js) for Vue I am setting up Vue like so:

import components from './components/components';

window.app = new Vue({
    el: '#vue',

    store,

    // etc.
});

My components.js imports all the components that I want to use as HTML snippets. Some of these components are import components on their own that are not directly set as components on my root instance.

What would be the best way to expose some data properties of certain single-file Vue components?

For instance I have a Search.vue component where I would like to send my first 3 objects from an array of results to Google Analytics:

// Expose this on `Search.vue`:

data: {
    // Filled with data from ajax request.
    results: []
}

My Vue instance is available globally. Is there an easy way to access a certain component perhaps by name or something?

Edit

So far the best option currently looks like accessing my property(which I have available inside my store) through a getter like so:

this.$store.getters.propertyINeed

Any suggestions on how to improve on this are welcome.

1
I see you use store, which I'm assuming you're using Vuex, can you put the data in the Vuex store instead?kevguy
And then just access it by using app.$store and calling my getters property on this object?Stephan-v
That's one way to do it, but I think if you can, you should do it inside the store (I'm writing a solution for it.)kevguy
@kevguy So I should expose the properties globally inside my store or something?Stephan-v
How do you send anything to Google analytics?kevguy

1 Answers

1
votes

I suggest you store the data you need in a Vuex store. As you can see, the srch-component has a computed property which gives the result and there's a watcher that will automatically dispatch the data to the store. Then you can use something like app.$store to access the data without tampering the components.

Note that you can also better manage the store using modules (link).

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    topSrchResult: []
  },
  mutations: {
    updateTopSrchResult: (state, payload) => {
      state.topSrchResult = payload
    }
  },
  actions: {
    UPDATE_TOP_SRCH_RESULT: ({ commit }, data) => {
        commit('updateTopSrchResult', data)
    }  
  }
})



Vue.component('srch-component', {
    template: `
      <div>
        <div>Input: <input v-model="inputVal" type="text"/></div>
        <div>Search Results:</div>
        <ul>
          <li v-for="item in srchResult">{{item}}</li>
        </ul>
      </div>
    `,
    data() {
        return {
          inputVal: '',
          dummyData: [
            'Scrubs', 'Hannah Montana', '30 Rock', 'Wizards of Waverly Place',
            'How I Met Your Mother', 'Community', 'South Park', 'Parks and Recreation',
            'The Office', 'Brooklyn Nine-Nine', 'Simpsons', 'Fringe', 'Chuck'
          ]            
        }
    },
    watch: {
        srchResult() {
          const payload = this.srchResult.length <= 3  ? this.srchResult : this.srchResult.slice(0,3)
          this.$store.dispatch('UPDATE_TOP_SRCH_RESULT', payload) 
        }
    },
    computed: {
      srchResult() {
        return this.dummyData
          .filter(
            (item) => item.toLowerCase().includes(this.inputVal.toLowerCase())
        )
      }
    }
})

const app = new Vue({
  el: '#app',
  computed: {
      topSrchResult() {
        return this.$store.state.topSrchResult 
      }
  },
  store
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.4.1/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>
<div id="app">
  <div>Top Results</div>
  <ul>
    <li v-for="item in topSrchResult">{{item}}</li>
  </ul>
  <srch-component></srch-component>
</div>