Earlier today John Ramon asked me a simple jQuery UI question: How do I keep links in tabs to load in the tab itself? I smugly answered, "That's easy" and directed him to the answer which is on the jQuery UI Tabs page. It's a common request for obvious reasons. I assumed that was the end of it until John threw something crazy into the works. A second link.
So imagine that you have a page with tabs. Here is a simple example. Note it already includes the "load links in tab in the tab" fix:
<script src="jquery-ui-1.8.11.custom/js/jquery-1.5.1.min.js"></script>
<script src="jquery-ui-1.8.11.custom/js/jquery-ui-1.8.11.custom.min.js"></script>
<link rel="stylesheet" href="jquery-ui-1.8.11.custom/css/ui-lightness/jquery-ui-1.8.11.custom.css" type="text/css" /> <script>
$(function() {
$( "#tabs" ).tabs({ load: function(event, ui) {
console.log("load event ran");
$('a', ui.panel).click(function() {
$(ui.panel).load(this.href);
return false;
});
} }); });
</script> <div id="tabs">
<ul>
<li><a href="#tabs-1">Nunc tincidunt</a></li>
<li><a href="test2.cfm">Aenean lacinia</a></li>
</ul>
<div id="tabs-1">
<p>Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Nunc tristique tempus lectus.</p>
</div>
</div>
The second tag, test2.cfm, is the one that will include our link:
<a href="test3.cfm">link to test3</a>
And here is test3.cfm:
<a href="test2.cfm">back to 2</a><br>
<cfoutput>#now()#</cfoutput>
So what I would expect is that when I click the link in the second tag, test3.cfm would load up. When I click the link to return, I'd expect test2.cfm to load back up again. However, that doesn't work. Check for yourself here: http://www.coldfusionjedi.com/demos/april12011/test.cfm And before you click - make note of the console.log message. If you are not using a browser with a console, please switch.
So - it didn't work, right? Why? My console.log runs when I open up the second tab, but does not run again when test3.cfm is loaded, which implies that jQuery UI didn't consider this a tab load. That kind of makes sense, but I'm having a hard time imagining the jQuery guys putting up a solution that works for one link only. It seems so... obviously wrong that I figure I must be missing something.
Archived Comments
For doing the same thing in dojo, I put the onclick handler on the div instead of the "a" element.
Something like this (apologies for formatting):
if( (currentEl.nodeName.toLowerCase()=='a' || currentEl.nodeName.toLowerCase()=='area')
&& currentEl.target.toLowerCase() != '_blank' && currentEl.target.toLowerCase() != '_top'){
evt.preventDefault(); // stop the link from unloading your page
if(typeof currentEl.onclick == 'undefined' || currentEl.onclick == null ) {
var navUri = parseUri(currentEl.href);
if(navUri.query.length > 0) navUri.query = "?" +navUri.query;
goNav(navUri.path + navUri.query);
}
}
Try putting the console.log() into the click handler for $('a', ui.panel) to make sure it is indeed handling the click inside of test3.cfm.
My guess would be that the selector you have is not catching links in the content that is loaded into the tab.
You might also try re-binding the handler to the tab load function? So it binds "a"s every time the tab content is loaded.
Actually..it is getting handled...when you click the link in test2.cfm...somehow it gets lost in test3.cfm.....
Never mind. Looks like that's what is supposed to be happening.
Does this handle form submissions as well? I had to add some custom code to the tab loading stuff in dojo to handle forms.
@Boyzoid: Added a console.log in the A handler (locally only), and it runs once also.
@Denstar: Sorry - what? Afaik - from what the docs say - that's what I did. By saying load:func x in the tab constructor, it should be run everytime a tab is loaded with stuff.
@denstar: For now I'm not going to worry about a form submission. Lets KISS. ;)
When I went to the test3.cfm I got ....
If <script> tags have a "type" attribute it should equal "text/javascript" or "application/javascript"
I think that's a best practices reco - but not a bug. I added them locally though - no difference.
Stupid KISS Question ... Is jquery included in test2 and test3?
No, it does not need to be. When you click tab 2, jQuery makes an XHR request to get test2.cfm. The result is injected into the DOM in the tab block.
Not tested. but. . .
what if you changed this
$(ui.panel).load(this.href);
to something like
$(this).parent().load(this.href);
how about using a delegate completely out side of the tab.
$('#ui-tabs01').delegate('a', 'click', function(event){
$('ui-tabs01').load(this.url);
})
The reason I suggested DOM traversal instead of ui.panel is that if you look at the rendered jQuery html for the tabs it shows tab1 with an href of #tabs-1 and tab 2 as #ui-tabs-1. May not be significant, just sayin..since the arget ids become tabs-1 and ui-tab-1 that maybe ui.panel is a bit confused
Try this ... As per http://api.jquery.com/live
$(function() {
$( "#tabs" ).tabs({
load: function(event, ui) {
console.log("load event ran");
$('a', ui.panel).live("click", function() {
$(ui.panel).load(this.href);
return false;
});
}
});
});
Try delegate. The following worked on my local copy of the files (changed to .htm):
$(function() {
$( "#tabs" ).tabs({
load: function(event, ui) {
$(this).delegate('a', 'click',
function(){
console.log("load event ran");
$(ui.panel).load(this.href);
return false;
}
);
}
})
});
However, I'd suggest adding a class to links that are to open within the tab, as you just know that someone will want to make sure that they can have some links open to replace the page. Plus remote links won't work, they won't be loaded into the page, so you'd have to check for the existence of the site's URL within the href to see if you should be trying to load. On my Firefox, it appears as if the page is being accessed, and it returns a 200 status code, but due to cross site access rule, it won't be added to the tab.
I think we have a winner here. It's working for me. I'm going to see if there is an easy way to provide this feedback to the team. Thanks Edward!
Thx Ray ... It's loading for me ...
$(function() {
$( "#tabs" ).tabs({
load: function(event, ui) {
console.log("load event ran");
$('a', ui.panel).live("click",function() {
console.log("The Tab Loaded");
$(ui.panel).load(this.href);
return false;
});
}
});
});
This seems like a case where maybe using an iframe is more appropriate...
eeewwwww iframes lol Thanks Edward for the help.
@David .... That works too ... :-)
$(function(){
$("#tabs").tabs({
load: function(event, ui){
console.log("Event Loaded");
$(ui.panel).delegate("a","click",function(){
console.log("The Tab Loaded Too ...")
$(ui.panel).load(this.href);
return false;
})
}
})
});
A bit late - but a) thank you guys and b) I've alerted folks at jQuery UI.
Hey Ray,
FWIW: delegate is a "better" way to handle this than live, both can work, but live is causing a lot more work to go on. I should have mentioned that in my original post. For more info, see the following article posted yesterday: http://jupiterjs.com/news/w...
I was asked to file a doc bug: http://bugs.jqueryui.com/ti...