Vuejs + Materializecss select field
Solution 1
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.
Solution 2
Vue.js 2.0
Template:
<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');
}
});
Solution 3
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() {
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>
</div>
<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>
</div>
Solution 4
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>
Solution 5
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.
Desprit
Updated on July 02, 2022Comments
-
Desprit almost 2 years
I have this code in my template:
<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> </div>
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