2015-11-14 15 views
7

Ho questo codice nel mio modello:Vuejs + Materializecss selezionare campo

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

Secondo documenti Materializecss, io chiamo $('select').material_select(); trasformare default Campo di selezione in qualcosa di Cutie. Inoltre, sostituisce i tag <select> e <option> con <ul> e <li>. Come risultato non posso accedere al valore di item.size nel file js ViewModel. Ho anche provato ad ascoltare per un clic sul campo opzione e chiamare il metodo OptionClick (che dovrebbe semplicemente allertare un messaggio), provato ad ascoltare selectChaned. Niente.

Come posso ottenere il valore dell'opzione in ViewModel?

p.s. solo per informazione: ho solo problemi con il campo selezionato. Campo di immissione per esempio funziona bene:

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

In ViewModel Sono in grado di accedere item.name

+0

può fornire un esempio in jsfiddle, jsbin, ecc? –

risposta

11

Sembra che Materialise non invii alcun evento quindi non sono riuscito a trovare una soluzione elegante. Ma sembra che la seguente direttiva Vuejs + jQuery soluzione sta lavorando:

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'); 
    } 
}); 

E poi nel codice HTML - si legano < selezionare> mediante v-selezionare invece di contro-modello.

+2

Il riferimento 'this' sta puntando a' window' nei metodi 'bind',' update' e 'unbind'. Difficoltà a impostare il valore. Stai usando l'ultima versione di Vue? –

+2

@EnmanuelRivera no, questo è stato fatto con la versione Vue precedente, non quella attuale –

0

Ho avuto un problema simile. Il problema qui è che devi rilasciare $('select').material_select(); solo dopo che il DOM della tua app Vue è pronto. Quindi puoi aggiungere un metodo pronto all'app Vue e includere $('select').material_select(); all'interno del tuo metodo pronto.

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

Basta fare in modo di includere Jquery, poi materialize.js seguita da Vue.js nel file HTML.

+0

Ciao e grazie per l'attenzione. Purtroppo questo non è quello che stavo cercando. Non ho avuto problemi con il rendering materializza il campo di selezione sulla pagina. La domanda era "come ottenere il valore dell'opzione selezionata". La risposta corretta è "usa direttiva personalizzata". Per ora sono passato alla classe del campo di selezione "browser-default". Quando avrò più tempo cercherò di costruire una direttiva per gestire i materiali da selezionare. – Desprit

0

Desidero includere un violino funzionante della direttiva select2 personalizzata che ho creato per il mio progetto. Supporta anche molteplici seleziona: 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> 
+1

Quindi hai fatto una risposta in base alla mia risposta e l'hai accettata tu stesso? :-) –

+0

@DenisMysenko Pensi davvero che sia basato sulla tua risposta? E tu non vedi le differenze? Anche se la tua risposta era vicina, non ha funzionato per me. Ho passato molto tempo a controllare molti esempi diversi per rendere finalmente il codice da documenti ufficiali di vue select2. Questo è il motivo per cui ho pubblicato una nuova risposta fornendo non solo alcuni copypaste casuali ma anche una parte fiddle e html funzionante. Ha senso? Bene per me sì, quando cerco lo stackoverflow per la risposta, preferisco quelli con esempio dal vivo. – Desprit

+0

non è un "copia-incolla casuale", è un pezzo di codice funzionante. e no, non ci sono differenze - la direttiva è la stessa. Non mi dispiace davvero, è strano vedere questo tipo di comportamento qui;) –

6

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> 

Componente:

"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'); 
    } 
}); 
2

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() { 
 
      \t 
 
       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 { 
 
    \t selected: '', 
 
\t  options:[ 
 
\t   {value:"v1",text:'description 1'}, 
 
\t   {value:"v2",text:'description 2'}, 
 
\t   {value:"v3",text:'description 3'}, 
 
\t   {value:"v4",text:'description 4'}, 
 
\t   {value:"v5",text:'description 5'}, 
 
\t  ] 
 
\t } 
 
\t } 
 
}); 
 
     
 
new Vue({ 
 
    el: '#exemple2', 
 
    data:function() { 
 
    return{ 
 
    \t selected: null, 
 
\t  options:[ 
 
\t   {value:"v1",text:'description 1'}, 
 
\t   {value:"v2",text:'description 2'}, 
 
\t   {value:"v3",text:'description 3'}, 
 
\t   {value:"v4",text:'description 4'}, 
 
\t   {value:"v5",text:'description 5'}, 
 
\t  ] 
 
\t } 
 
    }, 
 
    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>

+2

Si prega di aggiungere alcune spiegazioni accanto al codice. Le sole risposte al codice non sono benvenute. – Alexei

2

La risposta superiore era bello, ma non ha funzionato per Vue 2.

Ecco un aggiornamento che funziona (probabilmente ancora un po 'hacky). Ho spostato l'hook di jQuery in update() poiché la funzione bind è stata richiamata troppo presto per essere materializzata.

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> 
+0

purtroppo non funziona a meno che non carichi le opzioni tramite v-html, il loro loop non reinizializzerà la selezione. Qualche idea? –

0

VueJs2.4 V- Nessuna delle risposte di cui sopra fosse per elemento di selezione multipla. L'ho fatto lavorando attraversando le opzioni degli elementi selezionati. Questo non è un approccio corretto e un tipo di hack ma funziona.

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> 
     </div> 
     <h2>Your selected options</h2> 
     <p>{{$data.selected}}</p> 
     </div> 

     <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script> 
     <script src="https://unpkg.com/[email protected]/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> 
0

La possibile soluzione che ho trovato è quello di utilizzare un ingresso, e collegarlo a un contenuto di discesa. Funziona bene con Vue anche quando si crea dinamicamente un menu a discesa. E 'reattivo, che non devi emettere nessun altro evento per legare valori.

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

<style> 
    input{ 
     cursor: pointer; 
    } 
    .caret{ 
     float:right; 
     position: relative; 
     cursor: pointer; 
     top:-50px; 
    } 
    ul{ 
     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: '' 
        }, 
        id:{ 
         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>