Programatically adding tabs
I never thought about deleting a tabs instance, so that may indeed cause problems. What you can do (I'm pretty sure this will work too), is the following:
my_tabs = new Control.Tabs(...);
//anywhere else
my_tabs.containers['key'] = $('new_container');
my_tabs.links.push($('new_link'));
if your link href is "#linkname", then "key" should be "linkname"
I think I will add an addTab function at some point in the near future. You will still be responsibile for generating the HTML/DOM tree, but this will make it easier to attach things. Let me know if this leads you down the right path.
Posted May 17th, 2007 at 9:53am by ryan
Okay I think I'm getting close.
I hadn't been assigning ids to the links so I had to do some reworking on both client and server side to add this in, so that I could push the new link onto the links array.
By watching the tabs instance in Firebug I can see that these new array elements are being pushed on correctly, and I'm not getting the error from my responder any more either.
However it looks like the new tab needs to be set up with a responder as well, so I'm going to work on that now too.
Back to the battle... !
Posted May 17th, 2007 at 10:48am by bbodien
Woo hoo!
Okay, I deviated a bit from the manual array pushing approach you suggested because I couldn't work out how to handle the responders, but I eventually got this to work:
<!--Somewhere in the current tab content: -->
<a href="#" onclick="injectTab(this);return true;">make new tab!</a>
// global tab instance
var my_tabs = null;
// ON PAGE LOAD (whatever event handler function you may have):
my_tabs = new Control.Tabs($('my_tabs'));
Control.Tabs.addResponder({
beforeChange: function(control_tabs_instance,old_container){
// I have to empty the old container to reduce the DOM complexity, as my tab content divs contain
// a number of large html structures (tables, swf embeds etc).
// for some reason old_container == false here when this is called when reinitialising the tab object
// so create and use this reference instead
active_container = my_tabs.activeContainer;
active_container.update('');
},
afterChange: function(control_tabs_instance,new_container){
// ajax call to get new tab container's content
}
});
// END ON PAGE LOAD
// Add a new tab to an existing Control.Tabs instance
function injectTab(element) {
newTab = // new tab's list item markup
new Insertion.Bottom('my_tabs', newTab); // add to end of tab ul#my_tabs
newContent = // new tab's content (in my case an empty div for later AJAX population)
new Insertion.Bottom('my_pagecontainer', newContent); // add to your page container
// re-create tab object, overwriting the old one
my_tabs = new Control.Tabs($('my_tabs'), {
defaultTab: 'last' // open the newly created tab!
});
}
My only curiosity is as follows: in beforeChange if I use oldcontainer instead of assigning the result of tabs.activeContainer and using that, it works fine on page load, but when I run injectTab, beforeChange is parsed again during the call to new Control.Tabs, and this time through, old_container has a value of false.
I hope this makes sense, because my brain is completely fried. I don't even know JavaScript, yet somehow I've gotten this far running on vapour.
Posted May 17th, 2007 at 12:17pm by
Hi,
My way of doing this ended up being deleting the entire tabs element and retrieving a new one from the server. This has the disadvantage of losing the data that have been gathered so far in the older tabs, but it works...
I might take your injector into my code if I find time later!
Thanks, Lars
Posted May 22nd, 2007 at 12:18pm by larsb
Hi Lars,
That's another way of doing it - in my case any changes made to data in the existing tabs is saved in a database anyway, so I could in theory throw the tabs instance away completely and re-render the page from scratch with a new tab added, but this strikes me as a bit time expensive.
Ryan said he was planning to implement an addTabs function at some point, so you may want to wait. If not, my solution is working neatly here, let me know if you have any questions :)
Thanks, Ben
Posted May 23rd, 2007 at 5:27am by bbodien
I've got a Control.Tabs system up and running, which starts out with a handful of tabs.
The content for the inactive tabs is an empty div placeholder, and I use custom Responders to make AJAX calls to populate these placeholders when tabs are changed:
This works fine, and I can switch tabs back and forth no problem, with AJAX calls being fired of to fetch the new content.
What I want to do now is to programatically add new tabs when links in the active panel are clicked. So I've created an injectTab() function which uses Prototype Insertion to add the new li object in the tab bar, and a new div as a placeholder for the new tab's content.
When I attempt to rebuild the Tab system to incoroprate the newly added tab by calling new Control.Tabs($('tabcontainer')), I get an error: old_container.update is not a function (from the above code).
Is there a more appropriate way of reconstructing the Control.Tabs object once new tab elements have been manually inserted?
Many thanks!
Posted May 14th, 2007 at 10:26am by bbodien