Ollie
Ollie

Reputation: 1134

Vue select style functionality on a boostrap dropdown

I've just started using Vue, (which seems really nice) and I've run into an issue.

I have a bootstrap4 dropdown that I'm using to populate a hidden form (clicking on a dropdown-item saves the data value to the form below).

This is only done as I can't style the normal select/option dropdown as I would like.

This was all working fine, until I tried implementing vue, as I'm not using a select component directly the solutions offered in the vue select documentation don't seem to work.

Any help would be much appreciated.

Thanks in advance


html

<div class="dropdown">
    <button class="btn btn-secondary dropdown-toggle device-dropdown" type="button" data-toggle="dropdown" aria-haspopup="true"
        aria-expanded="false">
        All Devices
    </button>
    <div class="dropdown-menu" aria-labelledby="device-dropdown">
        <a class="dropdown-item" href="#" data-value="all">All Devices</a>
        <a class="dropdown-item" href="#" data-value="imac">iMac</a>
        <a class="dropdown-item" href="#" data-value="macbook">MacBook</a>
        <a class="dropdown-item" href="#" data-value="ipad">iPad</a>
        <a class="dropdown-item" href="#" data-value="iphone">iPhone</a>
    </div>

    <select name="device" class="hidden-device-dropdown">
        <option></option>
    </select>
</div>

js

// copies the selected dropdown element into a hidden select in the form 
$('.dropdown-menu').click(function (e) {
    e.preventDefault();
    // change button text to selected item
    var selected = $(e.target);
    $(".device-dropdown").text($(selected).text());

    // change option value (inside select) to selected dropdown
    var form = $("select.hidden-device-dropdown").children("option");
    $(form).val(selected.data("value"));
});

Edit: looks like v-on:click="device = '...'" might get me the functionality I'm after, is this a good way of doing it? seems to be duplicating a lot of code

Upvotes: 1

Views: 2018

Answers (1)

Bert
Bert

Reputation: 82459

I would suggest a component.

Vue.component("bs-dropdown",{
  props:["options", "value"],
  template:`
  <div class="dropdown">
    <button class="btn btn-secondary dropdown-toggle" 
            :class="id" 
            ref="dropdown"
            type="button" 
            data-toggle="dropdown" 
            aria-haspopup="true"
            aria-expanded="false">
      {{selected.text}}
    </button>
    <div class="dropdown-menu" :aria-labelledby="id">
      <a class="dropdown-item"  
         href="#" 
         v-for="option in options" 
         @click="selected = option">
        {{option.text}}
      </a>
    </div>
  </div>
  `,
  computed:{
    selected:{
      get() {return this.value},
      set(v){this.$emit("input", v)}
    },
    id(){
      return `dropdown-${this._uid}`
    }
  },
  mounted(){
    $(this.$refs.dropdown).dropdown()
  }
})

This component wraps the bootstrap functionality, which is what you typically want to do when integrating with external libraries.

Use it like so:

<bs-dropdown :options="devices" v-model="selected"></bs-dropdown>

Here is a codepen demonstrating it in action.

If/when you need the value, instead of copying it to a hidden select, the value is a data property bound with v-model. You can use that however you like.

Upvotes: 2

Related Questions