Help with a frustrating jQuery UI Tabs issue

This post is more than 2 years old.

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.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by denstar posted on 4/1/2011 at 9:43 PM

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);
}
}

Comment 2 by Scott Stroz posted on 4/1/2011 at 9:43 PM

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.

Comment 3 by denstar posted on 4/1/2011 at 9:44 PM

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.

Comment 4 by Scott Stroz posted on 4/1/2011 at 9:45 PM

Actually..it is getting handled...when you click the link in test2.cfm...somehow it gets lost in test3.cfm.....

Comment 5 by denstar posted on 4/1/2011 at 9:46 PM

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.

Comment 6 by Raymond Camden posted on 4/1/2011 at 9:46 PM

@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.

Comment 7 by Raymond Camden posted on 4/1/2011 at 9:47 PM

@denstar: For now I'm not going to worry about a form submission. Lets KISS. ;)

Comment 8 by Edward - Florida SEO posted on 4/1/2011 at 9:49 PM

When I went to the test3.cfm I got ....

If <script> tags have a "type" attribute it should equal "text/javascript" or "application/javascript"

Comment 9 by Raymond Camden posted on 4/1/2011 at 9:51 PM

I think that's a best practices reco - but not a bug. I added them locally though - no difference.

Comment 10 by Edward - Florida SEO posted on 4/1/2011 at 10:05 PM

Stupid KISS Question ... Is jquery included in test2 and test3?

Comment 11 by Raymond Camden posted on 4/1/2011 at 10:08 PM

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.

Comment 12 by MikeG posted on 4/1/2011 at 10:14 PM

Not tested. but. . .
what if you changed this
$(ui.panel).load(this.href);

to something like
$(this).parent().load(this.href);

Comment 13 by David posted on 4/1/2011 at 10:26 PM

how about using a delegate completely out side of the tab.

$('#ui-tabs01').delegate('a', 'click', function(event){
$('ui-tabs01').load(this.url);
})

Comment 14 by MikeG posted on 4/1/2011 at 10:26 PM

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

Comment 15 by Edward - Florida SEO posted on 4/1/2011 at 10:34 PM

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;
});
}

});

});

Comment 16 by Danilo Celic posted on 4/1/2011 at 10:39 PM

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.

Comment 17 by Raymond Camden posted on 4/1/2011 at 10:39 PM

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!

Comment 18 by Edward - Florida SEO posted on 4/1/2011 at 10:43 PM

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;
});
}

});

});

Comment 19 by Dan G. Switzer, II posted on 4/1/2011 at 11:10 PM

This seems like a case where maybe using an iframe is more appropriate...

Comment 20 by John Ramon posted on 4/1/2011 at 11:29 PM

eeewwwww iframes lol Thanks Edward for the help.

Comment 21 by Edward - Florida SEO posted on 4/2/2011 at 2:26 AM

@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;
})
}
})
});

Comment 22 by Raymond Camden posted on 4/7/2011 at 2:17 AM

A bit late - but a) thank you guys and b) I've alerted folks at jQuery UI.

Comment 23 by Danilo Celic posted on 4/7/2011 at 6:04 PM

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...

Comment 24 by Raymond Camden posted on 4/9/2011 at 9:29 PM

I was asked to file a doc bug: http://bugs.jqueryui.com/ti...