Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams
<div class="input-field col s6">
    <select v-on:change="selectChaned" v-model="item.size">
        <option value="" disabled selected>Choose your option</option>
        <option v-on:click="optionClicked" v-for="size in case_sizes" v-bind:value="{{ size }}">{{ size }}</option>
    </select> 
    <label for="size">Size</label>

According to Materializecss docs, I call $('select').material_select(); to transform default select field into something cutie. What it also does - it replaces <select> and <option> tags with <ul> and <li>. As a result I can't access value of item.size in my ViewModel js file. I even tried to listen for a click on option field and call optionClicked method (which should simply alert a message then), tried to listen for selectChaned. Nothing.

How can I get option value in ViewModel?

p.s. just for information: I only have problem with select field. Input field for example works fine:

<input placeholder="" name="name" type="text" class="validate" v-model="item.name">

In ViewModel I'm able to access item.name

It seems that Materialize doesn't dispatch any events so I couldn't find an elegant solution. But it does seem that the following Vuejs directive + jQuery workaround is working:

Vue.directive("select", {
    "twoWay": true,
    "bind": function () {
        $(this.el).material_select();
        var self = this;
        $(this.el).on('change', function() {
            self.set($(self.el).val());
    update: function (newValue, oldValue) {
        $(this.el).val(newValue);
    "unbind": function () {
        $(this.el).material_select('destroy');

And then in your HTML – bind <select> using v-select instead of v-model.

The this reference is pointing to window within the bind, update and unbind methods. Having difficulty setting the value. Are you using the latest version of vue? – Enmanuel Rivera Jan 8, 2017 at 0:06
<div v-text="selected"></div>
<material-select v-bind="selected = selected || options[0].value" v-model="selected">
     <option v-for="option in options" :value="option.value" v-text="option.name"></option>
</material-select>

Component:

"use strict";
Vue.component("material-select", {
    template: '<select><slot></slot></select>',
    props: ['value'],
    watch: {
        value: function (value) {
            this.relaod(value);
    methods:{
      relaod : function (value) {
          var select = $(this.$el);
          select.val(value || this.value);
          select.material_select('destroy');
          select.material_select();
    mounted: function () {
        var vm = this;
        var select = $(this.$el);
        select
            .val(this.value)
            .on('change', function () {
                vm.$emit('input', this.value);
        select.material_select();
    updated: function () {
        this.relaod();
    destroyed: function () {
        $(this.$el).material_select('destroy');
                if (binding.expression) {
                    if (binding.expression in vnode.context.$data) {
                        vnode.context.$data[binding.expression] = el.value;
                    } else if (vnode.context[binding.expression] &&
                            vnode.context[binding.expression].length <= 1) {
                            vnode.context[binding.expression](el.value);
                    } else {
                        throw new Error('Directive v-' + binding.name + " can not take more than 1 argument");
                else {
                    throw new Error('Directive v-' + binding.name + " must take value");
        unbind:function(el) {
            $(el).material_select('destroy');
new Vue({
  el: '#exemple1',
  data:function(){
    return {
    	selected: '',
	    options:[
	        {value:"v1",text:'description 1'},
	        {value:"v2",text:'description 2'},
	        {value:"v3",text:'description 3'},
	        {value:"v4",text:'description 4'},
	        {value:"v5",text:'description 5'},
new Vue({
  el: '#exemple2',
  data:function() {
    return{
    	selected: null,
	    options:[
	        {value:"v1",text:'description 1'},
	        {value:"v2",text:'description 2'},
	        {value:"v3",text:'description 3'},
	        {value:"v4",text:'description 4'},
	        {value:"v5",text:'description 5'},
  methods:{
    change:function(value){
        this.selected = value;
        alert(value);
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script>
<h4>vue js materialize</h4>
<h5>Exemple1</h5>
<div id="exemple1">
    <select v-material-select:change="selected" class="blue-text">
        <option value="" disabled selected ><slot>Defaut message</slot></option>
        <option v-for="option in options" :value="option.value">{{ option.text}}</option>
    </select>
<h5>Exemple2</h5>
<div id="exemple2">
    <select v-material-select:change="change" class="blue-text">
        <option  disabled selected ><slot>Choisir Votre Abonnement</slot></option>
        <option v-for="option in options" :value="option.value">{{ option.text}}</option>
    </select>

The top answer was nice but didn't work for Vue 2.

Here is an update of which works (probably still a little hacky). I moved the jQuery hook into update() as the bind function called too early for materialize.

Vue.directive("select", {
    "twoWay": true,
    update: function(el, binding, vnode) {
        if(!vnode.elm.dataset.vueSelectReady) {
            $(el).on('change', function() {
                vnode.context.$set(vnode.context, binding.expression, el.value);
            $(el).material_select();
            vnode.elm.dataset.vueSelectReady = true
    unbind: function(el, binding, vnode) {
        $(el).material_select('destroy');

HTML:

<select v-select=selected>
    <option value="" disabled selected>Choose your option</option>
    <option :value="item" v-for='item in items'>{{ item }}</option>
    <label>Materialize Select</label>
</select>
                sadly this doesn't work unless I load the options via v-html, looping through them won't reinitialize the select. Any ideas?
– secondman
                Sep 27, 2017 at 15:16

You can make the dynamic select in Vue + Materializecss work with simple hacks

$('#select').val(1).material_select(); // Set value and reinitialize materializecss select
mounted () {
   $("#select").change(function(){
            this.update_result.category = $("#select").val();
        }.bind(this)); // To set the user selected value to the data property 
   update_result.

If you are using meterializecss beta version the function name to initialize the select will differ.

I had a similar problem. The catch here is, you need to issue $('select').material_select(); only after the DOM of your Vue app is ready. So you can add a ready method to your Vue app and include $('select').material_select(); inside your ready method.

var vm = new Vue({
data: function() {
   locations: ["Clayton", "Mt Meigs", "Birmingham", "Helena", "Albertville", "Albertville", "Grant"]
ready: function() {
    $('select').material_select();

Just make sure you include Jquery first, then materialize.js followed by Vue.js in your html file.

Hi and thank you for attention. Unfortunately this isn't what I was looking for. I didn't have problem with rendering materialize select field on the page. The question was "how to get selected option value". The proper answer is "use custom directive". For now I just switched to "browser-default" select field class. When I get more time I will try to build a directive to handle materialize selects. – Desprit Jan 13, 2016 at 1:09

I want to include a working fiddle of custom select2 directive which I built for my project. It also supports multiple selects: fiddle

data: function() {
  return {
      names: [
      {id: 1, value: 'Alice'},
      {id: 1, value: 'Bob'},
      {id: 1, value: 'Simona'}
      myStudents: {
      names: ['Alice', 'Bob'],
directives: {
  'select': {
    twoWay: true,
    params: ['options'],
    bind: function () {
      var self = this
      $(this.el).select2().on('change', function() {
        self.set($(self.el).val())
    update: function (value) {
      $(this.el).val(value).trigger('change')
<select multiple v-select="myStudents.names" name="names" v-model="myStudents.names">
  <option v-for="name in names" value="{{ name.value }}">{{ name.value }}</option>
</select>
                @DenisMysenko Do you really think it is based on your answer? And you don't see differences? Even if your answer was close, it didn't work for me. I spent a lot of time checking many different examples to finally make code from official vue select2 docs work. This is why I posted a new answer providing not just some random copypaste but also working fiddle and html part. Does it make sense? Well for me yes, when searching stackoverflow for the answer, I prefer the ones with live example.
– Desprit
                Mar 19, 2016 at 9:33
                it's not a 'random copy-paste', it's a working piece of code. and no, there are no differences - the directive is the same. I don't mind really, it's just weird to see this kind of behaviour here ;)
– Denis Mysenko
                Mar 19, 2016 at 12:05
                No, it is not a working piece of code. Wanna show working one? Attach fiddle, jsbin or whatever you use. All vue select2 implementations look very similar, almost identical, and calling one of them yours is just selfishness. And yes, there actually are differences, I'm sure you can find them.
– Desprit
                Mar 19, 2016 at 17:06
                Desprit, you ask about how you should implement the MaterializeCSS select input element with Vue.js. @Denis Mysenko then gives you a working directive (I just tested it, and at least it works fine for me). Then you go ahead and answer your question with code for a "select2" checkbox.   To summarize it my opinion is that you didn't mark the most relevant answer as the correct one, instead you answered an other question ("how to write a Vue.js directive for a select2 checkbox?") and marked your answer as the correct one. I hope you see why Denis Mysenko find that a bit odd. :)
– jimutt
                Apr 5, 2016 at 13:38

v- VueJs2.4 None of the above answers were for multiple select element. I got it working by traversing the select element options. This is not a correct approach and kind of hack but works.

Plunker

    <h4>vue js materialize select</h4>
        <div class="row" id="app" style="padding-bottom:2em;">
        <div class="input-field col s12 m8">
          <select multiple v-material-select:change="selected">
                <option value="AngularJs">AngularJs</option>
                <option value="Bootstrap3">Bootstrap3</option>
                <option value="Bootstrap4">Bootstrap4</option>
                <option value="SCSS">SCSS</option>
                <option value="Ionic">Ionic</option>
                <option value="Angular2">Angular2</option>
                <option value="Angular4">Angular4</option>
                <option value="React">React</option>
                <option value="React Native">React Native</option>
                <option value="Html5">Html5</option>
                <option value="CSS3">CSS3</option>
                <option value="UI/UX">UI/UX</option>
              </select>
          <label>Technologies Used</label>
         <h2>Your selected options</h2>
       <p>{{$data.selected}}</p>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
        <script src="https://unpkg.com/vue@2.4.4/dist/vue.js"></script>
        <script>  Vue.directive("material-select", {
    bind: function(el, binding, vnode) {
      $(function() {
        $(el).material_select();
      var arg = binding.arg;
      if (!arg) arg = "change";
      arg = "on" + arg;
      el[arg] = function() {
        vnode.context.$data.selected = [];
        for (let i = 0; i < 12; i++) {
          if (el[i].selected === true) {
            vnode.context.$data.selected.push(el[i].value);
    unbind: function(el) {
      $(el).material_select("destroy");
           var app = new Vue({el: "#app",data: { selected: []},
     ready: function() {
          $("select").material_select(); }});</script>

The possible solution that I found is to use an input, and attach it to a dropdown content. It works well with vue even when you are dynamically creating dropdown. And its reactive, that you don't have to emit any other event to bind values.

Codepen: https://codepen.io/aaha/project/editor/DGJNLE

<style>
    input{
        cursor: pointer;
    .caret{
        float:right;
        position: relative;
        cursor: pointer;
        top:-50px;
      width: 100%;
</style>
<script>
    Vue.component('paper-dropdown', {
            template: '<div> \
                          <div class="input-field">\
                             <input type="text" class="dropdown-button" v-bind:data-activates="_id"\
                              v-bind:value="value"> \
                             <label>{{label}}</label> \
                          </div> \
                          <i class="material-icons caret">arrow_drop_down</i>\
                          <ul v-bind:id="_id" class="dropdown-content"> \
                             <li v-for="item in options" v-on:click="setselected"><a v-bind:value="item">{{item}}</a></li> \
                          </ul>\
                       </div>',
                watch: {
                    value: function(){
                        Materialize.updateTextFields();
                computed:{
                    _id: function(){
                        if(this.id != null) return this.id;
                        return Math.random().toString(36).substr(2);
                props: {
                    label:{
                        type: [String, Number],
                        default: ''
                    options:{
                        type: Array,
                        default: []
                    placeholder:{
                        type: String,
                        default: 'Choose your option'
                    value:{
                        type: String,
                        default: ''
                        type: String,
                        default: 'me'
                methods:{
                    setselected: function(e){
                        this.$emit('input', e.target.getAttribute("value"));                   
                mounted: function(){
                    $('.dropdown-button').dropdown({
                      inDuration: 300,
                      outDuration: 225,
                      constrainWidth: false, // Does not change width of dropdown to that of the activator
                      hover: false, // Activate on hover
                      gutter: 0, // Spacing from edge
                      belowOrigin: false, // Displays dropdown below the button
                      alignment: 'left', // Displays dropdown with edge aligned to the left of button
                      stopPropagation: false // Stops event propagation
    </script>
  const self = this;
  $(this.$el).on("change", function(e) {
    self.$emit('input', this.inputValue);
.....
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.