Vue - using $emit, .sync pattern with not required props

Viewed 1073

If I have a non-required prop is it possible to emit (using $emit('update:<prop name>', value) ) it in the child component and have it update to the emitted value without the parent component having :<prop name>.sync="<data name>"

example child component:

Vue.component('child-component', {
  props: {
    bar: {
      type: String,
      default: () => 'foo'
    }
  },

  methods: {
    doSomethingWithBar () {
      this.$emit('update:bar', 'bar')
    }
  },

  template: '<button @click="doSomethingWithBar">{{ bar }}</button>'
})

example parent:

<child-component /> <!-- notice no :bar.sync -->

Example on codepen: https://codepen.io/anon/pen/jXaGJg

My current solution is:

Vue.component('child-component', {
  props: {
    bar: {
      type: String,
      default: () => 'foo'
    }
  },

  data () {
    return {
      innerBar: null
    }    
  },

  mounted () {
    this.innerBar = this.bar
  },

  methods: {
    doSomethingWithBar () {
      this.innerBar = 'bar'
    }
  },

  template: '<button @click="doSomethingWithBar">{{ bar }}</button>',

  watch: {
    bar () {
      this.innerBar = this.bar
    },

    innerBar () {
      if (this.innerBar !== this.bar) {
        this.$emit('update:bar', this.innerBar)
      }
    }
  }
})

But this requires a lot of unnecessary code and I am quite sure there is a better idea.

UPDATE: (Actual context)

I am designing an audio component that wraps controls and playing Audio.

Example for audio.loop (I would have to do something similar to currentTime, paused, volume, etc.):

export default {
  props: {
    loop: {
      type: Boolean,
      default: () => false
    },
    audio: {
      required: true,
      type: HTMLAudioElement
    },
  },

  data () {
    return {
      innerLoop: null
    }
  },

  methods: {
    toggleLoop () {
      if (this.innerLoop) {
        this.innerLoop = false
      } else {
         this.innerLoop = true
      }
    }
  },

  watch: {
    loop () {
      this.innerLoop = this.loop
    },

    innerLoop () {
      this.audio.loop = this.innerLoop
      if (this.innerLoop !== this.loop) {
        this.$emit('update:loop', this.innerLoop)
      }
    }
  }
}

This works but is there a better way?

0 Answers
Related