mx_code
mx_code

Reputation: 2517

How to bind a value to custom inputs in vue.js?

I'm creating a dropdown input using simple div elements. Cause css customisation on native tag is limited.

<div class="dropdown">
  <button @click="open=true">{{selected}}</button>
  <div  class="dropdown-content" v-if="open">
    <p @click="setValue()">Hello World!</p>
    <p>Hello World!</p>
    <p>Hello World!</p>
  </div>
</div>

So when the user clicks on the button setValue() method will be fired.

export default {
  name: "dropdown",
  components: {},
  props: [
    "value",
  ],
  data() {
return {
selected : null }
  },
  computed: {},
  mounted() {},
  methods: {
    setValue(value) {
      this.open = false;
      this.selected = value;
      this.$emit("selected", value);
    },
  },
};

So my question is that how can I bind v-model to this custom component from the outside:

Like this :

<dropdown v-model="dropvalue"></dropdown>

Currently I'm listening to the emit event from the component and manually updating the input value... (something like ...<dropdown @selected="changeValue($event)"></dropdown> Instead how can I implement something like metioned above ... using v-model???

Upvotes: 1

Views: 1748

Answers (3)

Omar Mir
Omar Mir

Reputation: 1624

Just as an update, I don't think this works in Vue 3 (at least it didn't for me). Here is what I ended up doing:

CustomComponent.vue

<input
    type="text"
    id="simple-search" @input="setValue"
    class="w-full pl-8 p-2 border border-inputborder text-icongrey rounded-lg outline-none"
    :placeholder=placeholder
>

The setValue function (I'm using TS but you can just skip the typing for vanilla):

const emit = defineEmits(['update:modelValue'])    
const setValue: (event: Event) => void = (event: Event) : void => emit('update:modelValue', (event.target as HTMLInputElement).value)

PageYouWantToUseYourCustomComponent.vue

Somewhere in the page:

<CustomComponent :placeholder="'This is just prop bound'" v-model="searchStr"></CustomComponent>

And in my setup script I have the searchStr as a reactive bit:

const searchStr = ref('') 

Upvotes: 0

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You should emit input event :

this.$emit("input", value);

Full example :

// ignore the following two lines, they just disable warnings in "Run code snippet"
Vue.config.devtools = false;
Vue.config.productionTip = false;


Vue.component('dropdown', {


  name: "dropdown",

  props: [
    "value","options"
  ],
  data() {
    return {
      selected: null,
      open:false
    }
  },

  methods: {
    setValue(value) {
      this.open = false;
      this.selected = value;
      this.$emit("input", value);
    },
  },

  template: `<div class="dropdown">
  <button @click="open=true"> {{selected || 'Select a value'}}</button>
  <div v-if="open" class="dropdown-content">
     <p v-for="option in options" @click="setValue(option)">
     {{option}}
     </p>
  </div>
</div>`
})

let app = new Vue({
  el: '#app',
  data() {
    return {
      val: 'a'
    }
  }

})
.dropdown-content{
box-shadow :0 0 10px #aaa;
padding:10px;

}

.dropdown-content p{
 cursor:pointer;
 padding:4px;
}

.dropdown-content p:hover{
  background:#efefef
}
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>


<div id="app" class="container">
  <dropdown v-model="val" :options="['aaa','bbb','hello']"></dropdown>

  <h2>{{val}}</h2>
</div>

Upvotes: 2

Ilijanovic
Ilijanovic

Reputation: 14904

You can use v-model on custom components you need to emit input

this.$emit("input", value)

Vue.component("dropdown", {
   template: `<div class="dropdown">
                  <button @click="open=true">{{value}}</button>
                  <div  class="dropdown-content" v-if="open">
                    <p v-for="option in options" @click="setValue(option)">option: {{ option }}</p>
                  </div>
              </div>`,
  props: ["value"],
  data() {
    return {
      open: false,
      options: [1,2,3,4]
    }
  },
  methods: {
    setValue(value) {
      this.open = false;
      this.$emit("input", value);
    },
  },
              
})



new Vue({
   el: "#app",
   data: {
      selectedOption: 2
   }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <p>selected: {{ selectedOption }}</p>
  <dropdown v-model="selectedOption" />
</div>

Upvotes: 2

Related Questions