[Vuejs]-Set same value for sibling component's select

2đź‘Ť

âś…

I considered a little bit after my original answer and have come up with something I think is a little bit more real world than the example fiddle provided in the original question; specifically it is easy to make all the selects reflect the same value if they are all using the same source value, however I expect in a real world scenario each component would be independently bound to a single client. Each client would want their individual value to change, with the one caveat that if a “master” client changed, then all non-master clients should change to the master client’s value.

To that end, this might be a case where I think a component specific bus is appropriate. The master would emit an event when it’s value changed and the the other clients would set their value with respect to the master.

console.clear()

const MyCompBus = new Vue()

Vue.component('my-comp', {
  props: ['val', 'master'],
  computed:{
    selected:{
      get(){return this.val},
      set(v){
      	this.$emit('update:val', v)
     		if (this.master)
        	MyCompBus.$emit("master-updated", v)
     }
    }
  },
  methods:{
  	onMasterUpdated(newMasterValue){
      if (this.master) return
      this.selected = newMasterValue
    }
  },
  created(){
  	MyCompBus.$on('master-updated', this.onMasterUpdated)
  },
  beforeDestroy(){
  	MyCompBus.$off('master-updated', this.onMasterUpdated)
  },
  template: `
		<div>
      <div>
        <label>Status</label>
        <select v-model="selected">
          <option selected="" disabled="" value="0"></option>
          <option value="xxx">Xxx</option>
          <option value="yyy">Yyy</option>
          <option value="zzz">Zzz</option>
        </select>
      </div>
    </div>
  `,
})

new Vue({
  el: '#app',
  data:{
    masterValue: null,
    clients:[
      {id: 1, selectedValue: null, master: true},
      {id: 2, selectedValue: null},
      {id: 3, selectedValue: null},
      {id: 4, selectedValue: null},
    ]
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <my-comp v-for="client in clients" 
           :val.sync="client.selectedValue" 
           :master="client.master" 
           :key="client.id">
  </my-comp>
  {{clients}}
</div>

Original Answer

Bind them all to the same value using v-model.

Vue.component('my-comp', {
  props: ['value'],
  computed:{
    selected:{
      get(){return this.value},
      set(v){this.$emit('input', v)}
    }
  },
  template: `
    <div>
      <div>
        <label>Status</label>
        <select v-model="selected">
          <option selected="" disabled="" value="0"></option>
          <option value="xxx">Xxx</option>
          <option value="yyy">Yyy</option>
          <option value="zzz">Zzz</option>
        </select>
      </div>
    </div>
  `,
})

And in the template:

<my-comp v-for="x in 2" v-model="selectedValue" :key="x"></my-comp>

Here is the updated fiddle.

If you want to stick with val as the property you can use .sync instead.

Vue.component('my-comp', {
  props: ['val'],
  computed:{
    selected:{
      get(){return this.val},
      set(v){this.$emit('update:val', v)}
    }
  },
  template: `
    <div>
      <div>
        <label>Status</label>
        <select v-model="selected">
          <option selected="" disabled="" value="0"></option>
          <option value="xxx">Xxx</option>
          <option value="yyy">Yyy</option>
          <option value="zzz">Zzz</option>
        </select>
      </div>
    </div>
  `,
})

And in the template:

<my-comp v-for="x in 2" :val.sync="selectedValue" :key="x"></my-comp>

Example fiddle.

If you want just one of them designated as a “master” select, then add a property that does so.

Vue.component('my-comp', {
  props: ['val', 'master'],
  computed:{
    selected:{
      get(){return this.val},
      set(v){if (this.master) this.$emit('update:val', v)}
    }
  },
  template: `
    <div>
      <div>
        <label>Status</label>
        <select v-model="selected">
          <option selected="" disabled="" value="0"></option>
          <option value="xxx">Xxx</option>
          <option value="yyy">Yyy</option>
          <option value="zzz">Zzz</option>
        </select>
      </div>
    </div>
  `,
})

And in the template:

<my-comp v-for="x in 5" :val.sync="selectedValue" :master="1 == x" :key="x"></my-comp>

Example fiddle.

👤Bert

Leave a comment