Using jQuery Tabs and ASP.NET MVC Partial Views For AJAX Goodness

February 23rd, 2010 by Kevin Leave a reply »

Note: This example was built using jQuery UI 1.7.2 (which packages jQuery 1.3.2).  If you use jQuery 1.4.1, this example will break.  jQuery UI 1.8 will fix.  Thanks to mvcuser.  http://dev.jqueryui.com/ticket/5065

In my current project, I’ve had the need to use a Tab control but the data inside of the tabs was way too hefty to load initially when page loaded for the first time.  Luckily, the jQuery Tab control provides this functionality for me already.  However, I needed to find a way to easily organize the tab content on the server.  ASP.NET MVC provides a great structure for this called Partial Views.

In this quick tutorial, I’ll give you a run down on how to set up a jQuery tab control and how to configure ASP.NET MVC Partial Views to work with the tab controls.

Configuring Your View

Since we’re working in ASP.NET MVC, we’re going to talk about our pages in the form of Views.  I’m working with the default “blue screen” ASP.NET MVC application.  After you’ve downloaded and linked the jQuery and jQuery UI scripts to your View (either in the view itself or in the master page), you’re going to add the following code:

    <script type="text/javascript"><!--mce:0--></script>
 
<div id="tabContainer">
 
<ul>
 
	<li><a href="/Home/GetHomeTab">Home</a></li>
 
 
	<li><a href="/Home/GetProductTab">Products</a></li>
 
 
	<li><a href="/Home/GetContactUsTab">Contact Us</a></li>
 
</ul>
</div>

This code replaces the existing content section in the Index view for the Home controller.  The most interesting part of this is the tabContainer div.  Inside of it, we’ve declared a unordered list, and several list items.  jQuery UI uses this determine how to format the tab control.

You’ll notice that inside of our list items (<li> tags) that we’re using links to various action links (and yes, I know I could use HTML helpers to build these links for me).  Now, we need to build the views that will be rendered inside the tabs.

Here is an example of building the GetHomeTab view.  Nothing special, but make sure that you select Create a partial view.  Partial views won’t have any of the HEAD, HTML, or BODY fluff inside of them.  These are perfect for our tabs.

image

Repeat for GetProductTab and GetContactUsTab.  Add a few lines of text to the views in so you know they’re working.  Here’s an example of what my GetHomeTab looks like:

&lt;%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %&gt;
 
<h1>Home</h1>
 
 
You're inside the Home tab, which was rendered via a partial view!

Before we can test, we need to update our Controller to return the views as requested.  Here’s the additions you’ll make to your Home controller:

public ActionResult GetHomeTab()
{
return PartialView();
}
public ActionResult GetProductTab()
{
return PartialView();
}
public ActionResult GetContactUsTab()
{
return PartialView();
}

You can attach models to these views and they’ll work fine.  Build and run the application.

image

And to prove that everything is working as AJAX call backs, we can look at FireBug:

image

Firebug will show that when I clicked on the Contact Us tab, it automatically made an AJAX call to our Home controller and retrieved the partial view.

That’s awesome Kevin, now Why?

Tabs can be bloaty.  They contain a ton of markup for rendering inside the tab, and all this needs to be maintained within a single file.  By loading our pages dynamically, we’re eliminating the strain on the server.  Imagine we have 10 tabs.  If the user only needs to access two of them, we’re wasting bandwidth by downloading all the additional markup.  Then the browser needs to render it and store it, waiting for the user to come along and do something.  In an AJAX environment, we only download tabs as needed.  Much less strain on the server.

Second, maintaining 11 small files is much easier than maintaining 1 large file.  If you need to make a change to the Contact Us tab, you don’t need to go searching through the main page to find it.  Instead, you locate the GetContactUsTab view and make your changes!

I hope you’ve learned something from this, and maybe implement it into your future projects.  I can tell you that it definitely makes a difference in my app where there are 10 tabs containing a lot of data.  Separating out all the pieces makes it much easier to maintain and update.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
Advertisement

21 comments

  1. Cool idea – although i think sometimes it is better to have the content right there so that a high latency connection doesn’t affect tab switching.

    Although for interactive content tabs this is definitely a win…

    thanks for the toolbelt item :-)

  2. “d all this needs to be maintained within a single file”
    False. You can keep separate parts in partials.

    “By loading our pages dynamically, we’re eliminating the strain on the server.”
    Not proven and not necessarily.
    In fact your example it will be much better to load all 3 tabs on that page within one request (Home page) instead of 3.

    Another very important thing about this particular example is that you really should separate Products and Contact Us pages. The reason is that a User can have JavaScript disabled (and it is still common), then they will see link to Products & Contact Us. Clicking it they will see nothing except the plain content of those parts only. No layout, nothing. Usual user just leaves the site.

    So the point is that it should not be overused. In fact the example for Home, Products, Contact Us might be the worst one IMO.
    Something like Product, Reviews, Recommendations would probably be a better sample.

    Cheers,
    Dmitriy.

    • Jon Hilton says:

      But in the controller you could check if the request was an AJAX request and return the view complete with master page if not.

      So if a user doesn’t have javascript, they would see a link, which (when clicked on) would give them a page complete with layout and style.

  3. mvcuser says:

    Doesn’t seem to be working with jQuery 1.4.1, are you using 1.3.2?

    Thx

  4. mvcuser says:

    Sorry for the multiple posts, turns out 1.8 is out but not in \stable\ condition

    http://blog.jqueryui.com/2009/08/jquery-ui-18a1/

  5. mvcuser says:

    Since MVC2 RC2 comes with jQuery 1.4.1, that’s how i came across the issue. Doesn’t work with IE8 or FF either.

    In IE8, i first get the following error (this might be a different issue):

    Message: HTML Parsing Error: Unable to modify the parent container element before the child element is closed (KB927917)
    Line: 0
    Char: 0
    Code: 0

    And the tab URL appends “#ui-tabs-[object Object]” which is incorrect, i’ll download the jQuery UI 1.8 release and let you know if it’s working.

  6. be7 says:

    Any idea how to get an ajaxLoader animated GIF to display *inside* the tab? For example:

    $(function() {
    $(“#ajaxLoader”).ajaxStart(function() {
    $(this).show();
    }).ajaxStop(function() {
    $(this).hide();
    });
    });

    I can only get it to work if the ajaxLoader GIF is outside the tab content. Also, should this code be put in the partial view, or in the Index view?

  7. Chris says:

    This is a very cool feature. Wish it was in standard ASP.NET though. I’ve not used MVC in earnest yet, but this effectively is like an old ‘include’ from classic ASP.
    A much better way of implementing when using tabs.
    Nice article.

  8. Mike says:

    I really like this affect, great article.

    One question though. I know you’ve allowed for the history to work when you click the back button but when I click a few pages then click back until I get to the webpage that doesn’t have a #anchor in the URL (the initial page) then it just shows the animation spinning.

    Is this an issue? And if so, does anyone know how to correct it?
    ——————————————-
    Avermedia trots out AVerLife Cinema media playing set-top box

  9. Greg says:

    so, it seems to me that either the examples are incomplete and/or I am doing something wrong (quite probably the latter)… when I implement this as shown, (a) the LIs are not rendered as tabs and (b) when links are clicked the .ascx content is just loaded sequentially into the page,

    I have verified that my links to JQ 1.42 and UI 1.84 are correct, the scripts are being loaded and I re-downloaded UI just to be sure that ‘Tabs’ was included.

    jQTabs is called with this I assume:

    $(document).ready(function () {
    $(“#tabContainer”).tabs();
    });

    Any ideas?

    • Kevin says:

      Hey Greg,
      Shoot me an email at kevin at kevgriffin dot com along with an example snippet. I’ll take a look and see what’s causing the issue.

      Kevin

    • Kyle Russell says:

      Double check which jQuery files you are loading. The documentation says UI Core is required so I was loading only jquery.core.ui and jquery.ui.tabs. Once I realized UI Core meant all the core files it worked. Basically you may be missing jquery.ui.widget. It makes sense now but the jQuery website should be a bit more clear which libraries are required for certain functions.

Leave a Reply