Tôi nghĩ tôi muốn cập nhật câu hỏi này với một giải pháp mới mà tôi đã bắt đầu sử dụng. Trước đây tôi đã sử dụng FIT của RP Niemeyer http://jsfiddle.net/rniemeyer/dsKbH/ làm cơ sở cho việc thêm/xóa các tab giao diện người dùng jQuery gắn với KO observableArray.
Trong vài tháng qua, tôi đã gặp phải một số sự cố trong ứng dụng liên quan đến A) SetTimeout() trì hoãn và B) Phá hủy và tạo lại tiện ích con tab mỗi lần cập nhật được kích hoạt. Vì vậy, tôi đã đưa ra một cách tiếp cận khác để tránh những vấn đề này, và IMHO, là một kỹ thuật thanh lịch hơn.
http://jsfiddle.net/LatencyMachine/XJPJZ/
Ý tưởng chính là để giới thiệu một phong tục rất đơn giản ràng buộc gọi là "TabPanel" và một widget tương ứng mà bạn liên kết với tab div nội dung bảng điều khiển của bạn. Khi KO tạo và loại bỏ các div này dựa trên observableArray của bạn, ràng buộc tabPanel đảm bảo cập nhật jQueryUI.tabs bằng cách sử dụng phương thức "refresh". Điều này làm việc rất nhiều mượt mà hơn tôi cố gắng để có được các tab để cập nhật (và vào đúng thời điểm) trong các ràng buộc của phần tử container.
mã có liên quan từ fiddle
/**
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);
}
});