rhoward
rhoward

Reputation: 313

Vue: Accessing data from an unmounted component

I have an issue where I want to retreive data from a child component, but the parent needs to use that data, before the child is mounted.

My parent looks like this

<template>
    <component :is="childComp" @mounted="setData"/>
</template>
<script>
    data : {
        childComp : null,
        importantData : null
    },
    methods : {
        addComponent : function() {
            this.prepareToAdd(this.importantData);
            this.childComp = "componentA"; //sometimes will be other component
        },
        setData : function(value) {
            this.importantData = value;
        },
        prepareToAdd : function(importantData){
            //something that has to be run before childComp can be mounted.
        }
    }
</script>

My child (or rather, all the potential children) would contain something like this:

<script>
    data : {
        importantData : 'ABC',
    },
    created: function() {
        this.$emit('mounted', this.importantData);
    },
</script>

This clearly doesn't work - importantData is set when the childComponent is mounted, but prepareToAdd needs that data first.

Is there another way of reaching in to the child component and accessing its data, before it is mounted?

Upvotes: 1

Views: 2409

Answers (2)

Roy J
Roy J

Reputation: 43899

You can use $options to store your important data and have it available in beforeCreate. You can also use it to initialize a data item, and you can emit data items in created (you don't have to initialize from $options to emit in created, I'm just pointing out two things that can be done). The $options value is, itself, reactive (to my surprise) and can be used like any data item, with the added benefit that it is available before other data items.

new Vue({
  el: '#app',
  methods: {
    doStuff(val) {
      console.log("Got", val);
    }
  },
  components: {
    theChild: {
      template: '<div>Values are {{$options.importantData}} and {{otherData}}</div>',
      importantData: 'abc',
      data() {
        return {
          otherData: this.$options.importantData
        };
      },
      beforeCreate() {
        this.$emit('before-create', this.$options.importantData);
      },
      created() {
        this.$emit('on-created', this.otherData + ' again');
        // It's reactive?!?!?
        this.$options.importantData = 'changed';
      }
    }
  }
});
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <the-child @before-create="doStuff" @on-created="doStuff"></the-child>
</div>

Upvotes: 2

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85653

My bad :(

We cannot get the data inside beforeCreated() hook.

Use the beforeCreate() hook instead of created() hook:

beforeCreate: function() {
   this.$emit('mounted', this.importantData);
},

We can use a watcher or computed option, so now your parent component would look:

data: {
  childComp: null,
  importantData: null,
  isDataSet: false
 },
 methods: {
  addComponent: function() {
   this.prepareToAdd(this.importantData);
   this.childComp = "componentA"; //sometimes will be other component
  },
  setData: function(value) {
   this.importantData = value;
   this.isDataSet = true;
  },
  prepareToAdd: function(importantData) {
   //something that has to be run before childComp can be mounted.
  }
 },
 watch: {
  isDataSet: function(newValue, oldValue) {
   if (newValue) {
    this.addComponent();
   }
  }
 }

I would suggest to use computed method as it caches the results. Use watcher when you have to perform asynchronous code.

Upvotes: 0

Related Questions