46

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'
    }
  }
})
6
  • 2
    Why do you need this? You can always just access this.computedData the same way you would access this.myComputed Commented Jun 1, 2017 at 23:00
  • It's not working with this. computedData, it's undefined. Commented Jun 1, 2017 at 23:02
  • 2
    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. Commented Jun 1, 2017 at 23:04
  • 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? Commented Jun 1, 2017 at 23:07
  • 2
    Sounds like your this isn't the component from the calling context Commented Jun 1, 2017 at 23:40

9 Answers 9

39

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

Sign up to request clarification or add additional context in comments.

Comments

12

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;
    }
  }
});

1 Comment

You can now do even... watch: { computedData: { handler: val => this.myComputed = val, immediate: true, } } And skip the duplicate created part altogether... See vuejs.org/v2/api/#watch
4
  1. Computed is already accessible in the template using {{ }}.

  2. But you can use the

watch:{
  //your function here
}

instead of computed

Comments

3

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>

Comments

2

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.

Comments

1

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://v2.vuejs.org/v2/guide/computed.html

Comments

0

Try to convert the computed in a method

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

  methods: {
    computedData(){
      return 'Hello World'
    }
  }
})

This is simple and it works (NOT reactive), but has a cost:

https://medium.com/notonlycss/the-difference-between-computed-and-methods-in-vue-js-9cb05c59ed98

Comments

0

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>

Comments

0

Yes, now you can use computed (composition api feature) in data by using computed function from vue. Here is an example.

<template>
  <div>
    <div>{{ person.info }}</div>
    <div><button @click="changePersonId">change id</button></div>
  </div>
</template>

<script>
import { computed } from 'vue';

export default {
  data: function() {
    return {
      person: {
        name: 'Evgeny',
        id: this.generateId(),
        info: computed(() => `${this.person.name} with id = ${this.person.id}`)
      }
    }
  },

  methods: {
    generateId() {
      return +`${Math.random()}`.slice(2);
    },

    changePersonId() {
      this.person.id = this.generateId();
    }
  }
}
</script>

It works absolutely as normal computed property. You can assign getters and setters as well:

info: computed({
  // arrow functions syntax must be for right this value
  get: () => {
    return `${this.person.name} with id = ${this.person.id}`
  },
  set: (value) => {
    this.person.name = value
  }
})

Imho, it is good an opportunity to group properties together and share it among child components without repeating computed properties there and to add some common computed props just as object property.

It is very useful, that we can use some vue 3 features in vue 2!

Read abount vue3 computed props

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.