29
votes

How can I use a computed property in the data or emit it via bus?

I have the following vue instance, but myComputed is always undefined but computedData is working correctly.

var vm = new Vue({
  data(){
    return{
      myComputed: this.computedData
    }
  },

  computed: {
    computedData(){
      return 'Hello World'
    }
  }
})
7
Why do you need this? You can always just access this.computedData the same way you would access this.myComputed - jfadich
It's not working with this. computedData, it's undefined. - Clinton Green
What I mean is you can access computed properties the exact same way you access data so there is not need to do what you're trying to do. - jfadich
So I'm trying to emit the computed property and that wasn't working like so bus.$emit('send-computed-data', this.computedData); any ideas then? - Clinton Green
Sounds like your this isn't the component from the calling context - roberto tomás

7 Answers

26
votes

Unfortunately, it is impossible to use computed property in data because of component creation timing: data evaluates Before computed properties.

9
votes

To make things as simple as possible, just do the work in watcher, unless you want to emit the changes to different components or there're a lot of variables you want to notify, then you may have to use Vuex or the event bus:

var vm = new Vue({
  data(){
    return{
      myComputed: '',
      computedData: 'Hello World'
    }
  },
  created() {
    this.myComputed = this.computedData;
  },
  watch: {
    computedData() {
      this.myComputed = this.computedData;
    }
  }
});
3
votes
  1. Computed is already accessible in the template using {{ }}.

  2. But you can use the

watch:{
  //your function here
}

instead of computed

2
votes

If you are using computed/reactive objects then it should be inside the computed and not inside the data.

Simply change your code to use computed instead of data

var vm = new Vue({
  data(){
    return{}
  },

  computed: {
    computedData(){
      return 'Hello World'
    },
    myComputed(){
     return this.computedData
    }
  }
})

you are trying to use data as computed and this shall not be. data doesn't act like computed object.

and it's not because of component creation timing. What if we changed the component creation timing ? this will not solve anything as data will take only the first computed value(only one) and will not update after.

2
votes

you can work just with the computed function

   var vm = new Vue({
      data(){
        return{
          //is not necessary
        }
      },
    
      computed: {
        computedData(){
          return 'Hello World'
        }
      }
    })

and in your template

<template>
  <div>{{ computedData }}</div>
</template>
1
votes

You are over-coding it. Computed props are accessible in the same manner as data props in your template.

var vm = new Vue({
  computed: {
    myComputed(){
      return 'Hello World'
    }
  }
})

In the template you have access to this just like you do to data:

<template>
  <div>{{ myComputed }}</div>
</template>

https://vuejs.org/v2/guide/computed.html

0
votes

computed is not available at the time data gets initialized.

If it should be a one-time thing (and NOT reactive), you could achieve this by setting the data at the moment where the computed property is available by using the created() hook:



export default {
  data: () => ({
    myDataBackend: '',
  }),
  computed: {
    computedData () {
      return 'Hello World'
    }
  },
  created() {
    this.$set(this, 'myDataBackend', this.computedData)
  }
}

Futher reading: Vue Documentation on Lifecycle Hooks


In case you are trying to work with v-model:

You could also use :value and some event like @change or @keyup in the element instead.

  • :value is the value which the input-element initially works with
  • After writing some letter in the input field, the @keyup event changes the data.
    Typically, events carry the updated form value in target.value
  • The changeMyData method sets the value
  • the computed property listens to the data change and the :value of the input field gets updated.

Note: I used data as a data store. But you could also use for example vuex instead.

<template>
<div>
  <input
    type="text"
    :value="computedData"
    @keyup="changeMyData"
  />
  <p>{{myDataBackend}}</p>
</div>
</template>

<script>

export default {
  data: () => ({
    myDataBackend: 'Hello World'
  }),
  methods: {
    changeMyData(evt) {
        this.$set(this, 'myDataBackend', evt.target.value)
        console.log('Changed the value to: ' + evt.target.value)
    }
  },
  computed: {
    computedData () {
      return this.myDataBackend
    }
  }
}
</script>