23

Im relatively new with VueJS, and I've got no clue about how to make some data globally available. I would like to save data like API endpoints, user data and some other data that is retrieved from the API somewhere where each component can get to this data.
I know I can just save this with just vanilla Javascript but I suppose there is a way to do this with VueJS. I may be able to use the event bus system to get the data but I don't know how I can implement this system to my needs.

I would appreciate it if somebody can help me with this.

StefanJanssen
  • 446
  • 1
  • 7
  • 18
  • There is a state management solution for Vue.js called Vuex: [documentation](http://vuex.vuejs.org/en/) It does everything you've mentioned. – Egor Stambakio Apr 03 '17 at 20:13

4 Answers4

49

Make a global data object

const shared = {
    api: "http://localhost/myApi",
    mySharedMethod(){
        //do shared stuff
    }
}

If you need to expose it on your Vue, you can.

new Vue({
    data:{
        shared
    }
})

If you don't, you can still access it inside your Vues or components if you've imported it or they are defined on the same page.

It's really as simple as that. You can pass shared as a property if you need to, or access it globally.

When you're just starting out there is no real need to get complicated. Vuex is often recommended, but is also often overkill for small projects. If, later, you find you need it, it's not that hard to add it in. It's also really for state management and it sounds like you just really want access to some global data.

If you want to get fancy, make it a plugin.

const shared = {
  message: "my global message"
}

shared.install = function(){
  Object.defineProperty(Vue.prototype, '$myGlobalStuff', {
    get () { return shared }
  })
}

Vue.use(shared);

Vue.component("my-fancy-component",{
  template: "<div>My Fancy Stuff: {{$myGlobalStuff.message}}</div>"
})

new Vue({
  el: "#app"
})

Now, every Vue you create and every component has access to it. Here is an example.

Bert
  • 80,741
  • 17
  • 199
  • 164
  • Great answer! In the codepen, you should console out the `$myGlobalStuff` instead of `$store`. – Abhishek Jain Aug 27 '17 at 17:32
  • @AbhishekJain Didn't even notice that :) Thanks! – Bert Aug 27 '17 at 17:34
  • Can you also shed light on how to make this shared object reactive? I tried editing `message` in the `mounted` callback but it did not update the view. – Abhishek Jain Aug 27 '17 at 17:39
  • 3
    @AbhishekJain If you take the first approach and expose `shared` on `data`, then the object properties will be converted into observed (reactive) values. If you take the plugin approach, the easiest way is to make `shared` a Vue: `const shared = new Vue({data:{message: 'my global message'}})`. Then `message` will be reactive. – Bert Aug 27 '17 at 17:45
  • Awesome, the latter approach did the trick! As an end note, do you think any of these two approaches is _better_ than the other one? (aside from the tedious work of exposing `shared` on every page's `data`, if we take the first approach) – Abhishek Jain Aug 27 '17 at 17:57
  • 1
    @AbhishekJain I'm not sure either is better. The plugin approach (especially when using a Vue as the shared object) is a *very* basic example of the approach Vuex takes. Under the hood in Vuex, the data is stored on a Vue object to make them reactive so you could argue it's in line with the "official" though process. – Bert Aug 27 '17 at 18:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/152956/discussion-between-abhishek-jain-and-bert). – Abhishek Jain Aug 27 '17 at 18:06
  • It seems that another way to make a particular field reactive is to just store a reference to that field under `data` of the component that wants to watch that field, instead of having to wrap the whole object around `Vue`. Guess both approaches are valid and it depends on the use case. – xji May 19 '20 at 21:31
  • 2
    You left out in the first example how to access the data in some child component. Thats what im looking for. – The Fool Sep 12 '21 at 17:49
  • @TheFool `this.$root.$data.shared.api` worked for me. from https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch – MG22 Apr 11 '22 at 00:56
  • also I had to set `var self = this`; outside the method, then use `self`(instead of `this`) inside of the method. – MG22 Apr 11 '22 at 18:40
3

You can use Store which will hold your application state.

const store = new Vuex.Store({
  state: {
    userData: []
  },
  mutations: {
    setUserData (state, data) {
      state.userData = data
    }
  }
})

With this you can access the state object as store.state, and trigger a state change with the store.commit method:

store.commit('setUserData', userData)

console.log(store.state.userData)
Saniya syed qureshi
  • 3,053
  • 3
  • 16
  • 22
1

Vue Mixin

// This is a global mixin, it is applied to every vue instance. 
// Mixins must be instantiated *before* your call to new Vue(...)
Vue.mixin({
  data: function() {
    return {
      get $asset() {
        return "Can't change me!";
      }
    }
  }
})

template

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
  In Root: {{globalReadOnlyProperty}}
  <child></child>
</div>

Or

Vue.prototype.$asset = 'My App'
Balaji
  • 9,657
  • 5
  • 47
  • 47
-2

I just use an environment.js file to store all of my endpoints as object properties.

var urls = {};
urls.getStudent = "api/getStudent/{id}";
etc...

Then I put reference to this environment.js file in the head of document on pages where I have VueJS code that needs access to those endpoints. Im sure there are many ways to do this.

victor
  • 802
  • 7
  • 12