I've been trying to use knockout to add/remove jQueryUI tabs but haven't had any luck. My view model is an array of Effect objects. I'd like a tab added/removed from the tab control as objects are added/removed from the view model.
Here's a JSFiddle someone started and I updated which shows what I'm looking to do JSFiddle example
It will break when you try to add a tab. I think I need to combine the template binding w/ a new custom binding that can destroy/recreate the tab control I think. I'd greatly appreciate any help. Thanks!
I thought I'd update this question with a new take on a solution that I started using. I had previously been using RP Niemeyer's fiddle http://jsfiddle.net/rniemeyer/dsKbH/ as the basis for dynamically adding/removing jQuery UI tabs bound to a KO observableArray.
Over the last few months I've bumped up against a few problems in my app related to A) The setTimeout() deferral, and B) The destroy and recreate of the tabs widget every time an update is triggered. So I came up with a different approach that avoids these issues, and IMHO, is a more elegant technique.
http://jsfiddle.net/LatencyMachine/XJPJZ/
The key idea is to introduce a very simple custom binding called "tabPanel" and a corresponding widget that you bind to your tab panel content divs. As KO creates and removes these divs based on your observableArray, the tabPanel binding makes sure to update the jQueryUI.tabs using it's "refresh" method. This works a lot smoother I think than trying to get the tabs to update (and at the right time) up in the container element's bindings.
Relevant code from 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);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With