1

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???

3 Answers 3

2

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>

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

8 Comments

But I'm not using any input elements /tags.. I'm using divs here...
If so how would I set back :value attribute so that selected value updates from the outside.
Yes i know , this valid when you use v-model with custom component
Oh. Ok. So If I set back the selected value from the outside inside the props ie. props : ['selected']... then if I set the selected value using the setValue(value) method as the user clicks... then it spits out error saying that props cannot be mutated/..
How can I bind to the selected value automatically from the outside ... like <div : value="item.selected"> or like <div :selected="item.selected">
|
2

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>

8 Comments

But I'm not using any input elements /tags.. I'm using divs here... If so how would I set back :value attribute so that selected value updates from the outside.
@mex just use this.$emit("input", value) and your v-model should work
Oh. Ok. So If I set back the selected value from the outside inside the props ie. props : ['selected']... then if I set the selected value using the setValue(value) method as the user clicks... then it spits out error saying that props cannot be mutated/..
How can I bind to the selected value automatically from the outside ... like <div : value="item.selected"> or like <div :selected="item.selected">
@mex remove this.selected = value; it will update automatically
|
0

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('') 

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.