Search code examples
javascriptvue.jsvue-resource

Accessing variable from main Vue.js instance in component VM


Here's a very simple Vue app that is passing a prop from the main VM to a component. This value is grabbed via vue-resource in my actual application.

https://jsbin.com/tazuyupigi/1/edit?html,output

Of course it works, but I'm struggling to access this value from the component VM itself.

https://jsbin.com/hurulavoko/1/edit?html,output

As you can see, my alert shows undefined. How can I fix this? Seems to be an issue with order of execution, but using compiled() or created() in place of ready() makes no difference.


Solution

  • It is a problem with order of execution. The main Vue instance isn't "ready" until the things inside it have been compiled. This includes the hello component.

    If you need to know that bar has been set before you use it, you can monitor for that in a couple of ways. You could $broadcast an event in the parent to let the child know that bar has been loaded. Or you could use a watch function in the child component to make changes when bar is updated.

    Your example does work if you $set bar in created(), however with vue-resource you're going to have a delay anyway, so you need to account for the fact that greeting won't be ready during the child's ready() function. You'll either have to design your DOM structure to handle the fact that greeting could be undefined, or you'll have to use an event or watch function to wait for it yourself.

    Example with $broadcast:

    Vue.component('hello', {
      template: 'From hello tag: {{ greeting }}',
      props: ['greeting'],
      ready: function() {
    
      },
      events:{
        'bar-ready':function(){
            alert(this.greeting)
        }
      }
    });
    new Vue({
        el: '#app',
        created: function() {
            this.$http.get('/path')
                .then(function(response){
                    this.$set('bar',response.data);
                    this.$broadcast('bar-ready')
                }.bind(this))
        }
    });
    

    $broadcast docs: https://vuejs.org/api/#vm-broadcast