2015-05-16 15 views
5

Problema:Knockout 'con' vincolanti e select2 in jQuery dialogo

Il select2 plugin jQuery non funziona quando viene utilizzato in una finestra di jQuery nidificato sotto un elemento che utilizza il ko with associazione dati. Rimuovere il binding with e select2 funziona correttamente. Se with è associato a una proprietà nidificata, smette di funzionare.

Background:

Quindi devo aver combattuto per la parte migliore di 3 ore cercando di ottenere select2 a lavorare su un modulo di dialogo jQuery .... parlare di pi $$ ing contro l'albero sbagliato proverbiale , Ho pensato che fosse puramente jQuery dialog e select2. Probabilmente ha funzionato fin dall'inizio con la correzione _allowInteraction. Fino a quando ho rotto il problema fino a semplici passaggi e la causa ha iniziato a rivelarsi. Il problema è con il binding with.

responsabilità

Scuse come io lavoro per una società stupida che blocca jsFiddle. Inoltre ho suddiviso la mia implementazione a scopo illustrativo in quanto il modello attuale è abbastanza grande.

// models 
 

 
function Department() { 
 
    this.name   = ko.observable('dept1'); 
 
    this.selectedTeam = ko.observable(new Team()); 
 
} 
 
    
 
function Team() { 
 
    this.name = ko.observable('team1'); 
 
} 
 
    
 
function MainModel() { 
 
    this.department = new Department(); 
 
    this.showTeam = function() { 
 
    $('#addTeamDialog').dialog('open'); 
 
    }; 
 
} 
 

 
// setup 
 

 
ko.applyBindings(new MainModel()); 
 
    \t 
 
$('#addTeamDialog').dialog({ 
 
    // fix allow select2 to work on the jq dialog 
 
    _allowInteraction: function (event) { 
 
    return !!$(event.target).is(".select2-input") || this._super(event); 
 
    } \t \t 
 
}); 
 
    \t 
 
$('#someList').select2({ 
 
    data: [ 
 
    { id: 0, text: 'enhancement' }, 
 
    { id: 1, text: 'bug' }, 
 
    { id: 2, text: 'duplicate' }, 
 
    { id: 3, text: 'invalid' }, 
 
    { id: 4, text: 'wontfix' } 
 
    ] 
 
});
<link href="http://code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet"/> 
 
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" /> 
 

 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.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/select2/4.0.0/js/select2.full.min.js"></script> 
 

 
<button data-bind="click: showTeam">Add Team</button> 
 

 
<div id="addTeamDialog"> 
 
    <fieldset data-bind="with: department"> 
 
    
 
    <div class="lite-dialog-field"> 
 
     <div class="label"> 
 
     <span data-bind="text: name"></span> 
 
     </div> 
 
     <div class="field"> 
 
     <input type="hidden" id="someList" /> 
 
     </div>  
 
    </div> 
 
     
 
    </fieldset> 
 
</div>

Rimozione del data-bind sulla fieldset e Select2 funziona bene.

Se lo data-bind su è impostato su department, select2 funziona correttamente.

Se lo data-bind su è impostato su department.selectedTeam select2 non funziona.

+0

Il codice che hai postato non abbastanza sembra essere sufficiente per riprodurre lo scenario (ad esempio non ci sono 'select's o relativo codice di qualsiasi tipo?). – Jeroen

+0

Cosa dà? L'input nascosto sul markup con id someList è il contenitore per il controllo select2. Nella sezione di installazione puoi vedere chiamo $ ('# someList'). Select2 ({..}). Questo converte questo elemento in select2 list. Mi sto perdendo qualcosa? Duro downvote .... –

+1

Sono corretto. Scuse. - Ho modificato la tua domanda un po ', altrimenti il ​​sistema non mi avrebbe permesso di annullare il mio voto. Ho anche ritirato il mio voto ravvicinato perché ora vedo che non ho fatto abbastanza sforzi per usare il codice postato per riprodurre il problema (anche se non sono ancora sicuro al 100% come farlo, ma altri potrebbero vedere le cose più chiare e essere in grado di aiutare). – Jeroen

risposta

4

Quando si lavora con Knockout, si consiglia vivamente di racchiudere librerie esterne come select2 in binding. Mentre li si inizializza solo una volta, i collegamenti come with, template o foreach possono modificare il DOM in qualsiasi momento.

si faccia il pericolo di una

  1. inizializzazione select2 troppo presto, quando Knockout non ha ancora reso nulla, o
  2. Knockout gettare via e ri-rendering del markup in un momento successivo, in modo che la vostra select2 non è improvvisamente legato più

Ad esempio, ciò sarebbe accaduto quando Department.selectedTeam viene modificato.

Ho trovato un binding select2 rapido e sporco da Knockouts rniemeyer himself here. Oltre a questo, ho modificato solo il markup select2 in uno standard <select> e reso MainModel.department in un osservabile appropriato per motivi di coerenza e sicurezza.

ko.bindingHandlers.select2 = { 
 
    init: function(element, valueAccessor) { 
 
     var options = ko.toJS(valueAccessor()) || {}; 
 
     setTimeout(function() { 
 
      $(element).select2(options); 
 
     }, 0); 
 
    } 
 
}; 
 

 
// models 
 

 
function Department() { 
 
    this.name   = ko.observable('dept1'); 
 
    this.selectedTeam = ko.observable(new Team()); 
 
}; 
 
    
 
function Team() { 
 
    this.name  = ko.observable('team1'); 
 
    this.values = ["red", "grey", "blue"]; 
 
    this.selected = ko.observableArray(["blue"]); 
 
}; 
 
    
 
function MainModel() { 
 
    this.department = ko.observable(new Department()); 
 
    this.showTeam = function() { 
 
    $('#addTeamDialog').dialog('open'); 
 
    }; 
 
}; 
 

 
// setup 
 

 
ko.applyBindings(new MainModel()); 
 
    \t 
 
$('#addTeamDialog').dialog({ 
 
    // fix allow select2 to work on the jq dialog 
 
    _allowInteraction: function (event) { 
 
    return !!$(event.target).is(".select2-input") || this._super(event); 
 
    } \t \t 
 
});
select { 
 
    width: 200px; 
 
}
<link href="http://code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet"/> 
 
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" /> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.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/select2/4.0.0/js/select2.full.min.js"></script> 
 

 
<button data-bind="click: showTeam">Add Team</button> 
 

 
<div id="addTeamDialog"> 
 
    <fieldset data-bind="with: department().selectedTeam"> 
 
    
 
    <select data-bind="options: values, 
 
         selectedOptions: selected, 
 
         select2: { placeholder: 'pick some colors' }"> 
 
    </select> 
 
     
 
    </fieldset> 
 
</div>

+0

Grazie janfoeh. Sfortunatamente non ha risolto il mio problema. La profondità della proprietà utilizzata con il contesto di associazione "con" sembra influenzare se il controllo select2 funziona o meno. Accolgo il tuo commento su come avvolgere tutte le librerie esterne in un'associazione e convertirò il mio appena possibile appena riesco a capire e risolvere questo problema –

+0

@AlanAlcock Sono un po 'confuso dal tuo commento se hai provato ad utilizzare select2 tramite un legame o no? Perché quello era il nocciolo della mia risposta. – janfoeh

+0

janfoeh: nella mia fretta non ho studiato correttamente la tua risposta, ma questo in realtà ha risolto il problema e, cosa più importante, mi ha insegnato ad apprezzare e racchiudere le librerie esterne nei gestori di binding. Molte grazie per il vostro aiuto. –