2015-12-21 17 views
7

Ho una casella di selezione in cui le opzioni e la selezione vengono gestite tramite Knockout.js. Voglio disegnare questo usando Materialise CSS.Reimposta Materialize.css casella di selezione dopo la rimozione dall'array di opzioni Knockout.js

Questo funziona correttamente per la visualizzazione iniziale della casella di selezione e quando le opzioni vengono aggiunte all'array osservabile 'options' di Knockout.js utilizzando il binding 'optionsAfterRender' per (ri) inizializzare dopo ogni opzione è stata aggiunta (sprecata , ma funziona).

Quando si rimuove un'opzione, Knockout.js non fornisce nulla di simile a "optionsAfterRender", quindi non esiste un modo ovvio per attivare una re-inizializzazione della magia Materialize CSS.

Domanda: Esistono opzioni non pazze che è possibile visualizzare?

Codice:

<select data-bind=" 

     options: options, 
     optionsText: function(item) { return optionsText[item] }, 
     value: displayedValue, 

     optionsAfterRender: function (option, item) { 
     setTimeout(function() { 
      $(option.parentElement).material_select(); 
     }, 0); 
     } 
    "> 
</select> 

(Il 'setTimeout' è necessario perché altrimenti l'opzione selezionata non viene raccolto.)

risposta

8

Un custom binding handler è più appropriato per l'integrazione di una componente di interfaccia utente personalizzato come material_select con KnockoutJS. Ecco un modo per costruire un tale gestore:

ko.bindingHandlers["materializeSelect"] = { 
 
    after: ['options'], 
 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
 
    // Initial initialization: 
 
    $(element).material_select(); 
 
    
 
    // Find the "options" sub-binding: 
 
    var boundValue = valueAccessor(); 
 
    
 
    // Register a callback for when "options" changes: 
 
    boundValue.options.subscribe(function() { 
 
     $(element).material_select(); 
 
    }); 
 
    }, 
 
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
 
    
 
    } 
 
}; 
 

 
function RootViewModel() { 
 
    var self = this, i = 2; 
 
    self.options = ko.observableArray([{id: 1, txt: "Option A"}, {id: 2, txt: "Option two"}]); 
 
    self.selectedOption = ko.observable(null); 
 
    
 
    // For testing purposes: 
 
    self.addOption = function() { self.options.push({id: ++i, txt: "Dynamic option " + i}); }; 
 
} 
 

 
ko.applyBindings(new RootViewModel());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.4/js/materialize.min.js"></script> 
 
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.4/css/materialize.min.css" rel="stylesheet"/> 
 

 
<select data-bind="materializeSelect: { options: options }, 
 
        options: options, 
 
        optionsText: 'txt', 
 
        value: selectedOption"> 
 
</select> 
 

 
<button data-bind="click: addOption">Add option dynamically</button>

Per essere onesto, mi sento che è un problema/omissione o forse anche un bug in MaterializeCSS che a quanto pare non si accorge select opzioni che cambia . Le librerie IIRC come Select2 e Chosen do hanno questa funzione.

In ogni caso, se MaterializeCSS opzioni sarebbe preavviso aggiunto dinamicamente in modo corretto, sarei ancora stuggest utilizzando un gestore personalizzato vincolante, solo molto più semplice uno: risposta

ko.bindingHandlers["materializeSelect"] = { 
    after: ['options'], 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
    $(element).material_select(); 
    }, 
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
    // Handle ViewModel changes of which MaterializeCSS needs custom 
    // notification here. 
    } 
}; 
+0

Io di solito chiamo '.material_select ('destroy');' prima di reiniziare per sicurezza.materializecss è un po 'giovane imho –

+0

Grazie per una risposta perfettamente funzionante - che ha anche risolto il problema successivo che ho avuto, come re-init dopo le modifiche di valore nel modello KO! – gzost

0

di Jeroen è grande e corretta, Volevo aggiungere un addendum usando i commenti SO, ma questo è meglio visto con una formattazione completa, penso.

Materialise sembra essere un po 'strano rispondere al binding disable quando inserito su una selezione, in particolare se tale disabilitazione dipende dall'aggiornamento di un altro osservabile a eliminazione diretta (che di solito è).

Io uso il seguente nella mia funzione di aggiornamento:

if(allBindings().disable != undefined && allBindings().disable == true){ 
    $(element).prop("disabled", true); 
} 
else{ 
    $(element).prop("disabled", false);  
} 

$(element).material_select(); 

inizialmente ho provato solo chiamando $(element).material_select() nella funzione di aggiornamento, ma sembra un po 'wishy annacquato, lavorando solo qualche volta. Cambiare esplicitamente la proprietà disabilitata sull'elemento sembra funzionare ogni volta.

Probabilmente c'è un modo molto più succinto per farlo, ma si spera che questo esempio illustri il punto: impostare esplicitamente la proprietà disabilitata in base allo stato del binding.

Non so se si riscontrano problemi simili usando altri attacchi, visible ecc., Ma se lo sono, è probabile che questi problemi possano essere risolti in modo simile.