Ho pensato di aggiornare questa domanda con una nuova versione di una soluzione che ho iniziato a utilizzare. In precedenza avevo utilizzato il violino di RP Niemeyer http://jsfiddle.net/rniemeyer/dsKbH/ come base per l'aggiunta/rimozione dinamica di schede dell'interfaccia utente jQuery legate a un ObservableArray KO.
Negli ultimi mesi mi sono imbattuto in alcuni problemi nella mia app relativi a A) Il differimento setTimeout() e B) Il distruggere e ricreare il widget schede ogni volta che viene attivato un aggiornamento. Così ho trovato un approccio diverso che evita questi problemi, e IMHO, è una tecnica più elegante.
http://jsfiddle.net/LatencyMachine/XJPJZ/
L'idea chiave è quella di introdurre una semplice associazione personalizzata chiamata "tabpanel" e un corrispondente widget che si associa alla scheda div contenuti del pannello. Poiché KO crea e rimuove questi div in base al tuo osservableArray, il binding tabPanel si assicura di aggiornare jQueryUI.tabs usando il suo metodo "refresh". Questo funziona molto più agevolmente penso che cercare di far aggiornare le schede (e al momento giusto) nelle associazioni degli elementi del contenitore.
relativo codice da violino
/**
KO Binding handler for a tabPanel div. Use this on divs that can appear/disappear and/or have their id change
depending upon an observable, usually an observableArray.
*/
ko.bindingHandlers.tabPanel = {
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
$(element).tabPanel(ko.toJS(valueAccessor()));
}
};
/**
This widget facilitates jQuery UI tabs that appear and disappear dynamically, usually as a result of MVVM like Knockout
Whenever this widget is created, the containing jQuery UI 'tabs' widget is refreshed so that it picks up the new tab
or drops the removed one.
This also facilitates dealing with id rename 'ripple' that occurs whenever a tab is removed due to the splice of an
observable array.
*/
$.widget("bw.tabPanel", {
options: {
id: null
},
_create: function() {
this.element.hide();
this.tabsElement = this.element.closest(".ui-tabs");
if(this.options.id) {
this.element.attr({id: this.options.id});
}
this.refreshTabs();
},
_destroy: function() {
if(this.options.id) {
this.element.attr({id: ""});
}
this.refreshTabs();
},
_setOption: function(key, value) {
var previousValue = this.options[key];
if(previousValue == value) return;
this.options[key] = value;
switch(key) {
case "id":
this.element.attr({id: this.options.id});
this.refreshTabs();
break;
}
},
/**
Invoke refresh on the parent tab to let it know that something has changed.
This also preserves the active index by setting it back to what it was before the refresh, which
may correspond to a different tab after the refresh.
*/
refreshTabs: function() {
var previousActiveIndex = this.tabsElement.tabs("option", "active");
this.tabsElement.tabs("refresh");
this.tabsElement.tabs("option", "active", previousActiveIndex);
}
});