Search code examples
javascriptjqueryasp.net-mvcjquery-pluginsjquery-ui-tabs

MVC 5: jQuery nested tabs are not displaying properly


Note: I am new to jQuery and tabs.

I am attempting to implement nested tabs with jQuery tabs in an MVC 5 web application. For some reason, the implementation is not working correctly and I assume there is a bug based on the behavior on the website and I suspect it is with how the active tab is being set.

When the user logs in, they are taken to a page for MainAppTabs. The two top tabs are Client and Account. The Client tab has nested tabs Client Info, Billing Selections, and About whereas the Account tab currently has only one nested tab called Account, which should only display a list of accounts.

With the current implementation below, the Account tab is the first tab to be displayed, as opposed to the Client tab, along with the nested Account tab. When I click on the Client tab then it will display fine with its nested tabs. However, when I click on the Account tab again then the page clears out and I must refresh the page (F5) in order to get the Account tab and its nested tabs to display. Also, the nested tab appears to be displayed twice where it is offset to the right and has a duplicate border, but the nested tab border and data spill outside of the parent tab border.

<div id="MainAppTabs">
    <ul>
        <li>@Html.ActionLink("Client", "ClientTabs", "ClientSetup")</li>
        <li>@Html.ActionLink("Account", "AccountTabs", "AccountSetup")</li>
    </ul>
</div>

<script>
    $(function () {
        $("#MainAppTabs").tabs({ active: 1 });
    });
</script>

ClientTabs:

<div id="ClientSetupTabs">
    <ul>
        <li>@Html.ActionLink("Client Info", "Edit", "ClientSetup")</li>
        <li>@Html.ActionLink("Billing Selections", "BillingSelections", "ClientSetup")</li>     
    </ul>
</div>

<script>
    $(function ()
    {
        $("#ClientSetupTabs").tabs({ active: 1 });
    });
</script>

AccountTabs:

<div id="AccountSetupTabs">
    <ul>
        <li class="active">@Html.ActionLink("Accounts", "Index", "AccountSetup")</li>
    </ul>
</div>

<script>
    $(function ()
    {
        $("#AccountSetupTabs").tabs({ active: 1 });
    });
</script>

Solution

  • This appears to be an issue with nested tabs, possibly because of the way the ajax calls are made and the scripts within your partials (scripts should not be in partials). To make this work, you can provide placeholder elements for the content of each tab and have the links reference those elements using id attributes.

    The html would be

    <div id="main"> // main (parent) tabs
      <ul>
        <li><a href="#client">Client</a></li>
        <li><a href="#account">Account</a></li>
      </ul>
      <div id="client"> // client tabs
        <ul>
          <li><a href="#client-info">Client Info</a></li>
          <li><a href="#billing-selections">Billing Selections</a></li>
        </ul>
        <div id="client-info">
          // content for client information
        </div>
        <div id="billing-selections">
          // content for billing selections
        </div>
      </div>
      <div id="account"> // account tabs
        <ul>
          <li><a href="#accounts">Accounts</a></li>
        </ul>
        <div id="accounts">
          // content for accounts
        </div>
      </div>
    </div>
    

    and to initialize the tabs

    $('#main').tabs({ ... }); // set options as required
    $('#client').tabs({ ... });
    $('#account').tabs({ ... });
    

    To display the content, use @Html.Partial() if the model in the view contains the data need to generate the partial, or @Html.Action() if you want to call a server method that returns the partial. For example, if the Edit() method of ClientSetupController returns the partial view to show in your Client Info tab, then

    <div id="client-info">
        @{ Html.RenderAction("Edit", "ClientSetup"); } // or @Html.Action("Edit", "ClientSetup")
    </div>
    

    Where the controller method is

    [ChildActionOnly]
    public PartialViewResult Edit
    {
        var model = ... // initialize you model for the view
        return PartialView("_Edit", model);
    }
    

    and _Edit.cshtml is a partial view and contains the html you want to display in the tab