Tab Interface Demo

This demo illustrates how to use a bit of clever client-side markup along with a Repeater to display parent/child data in a tab interface. Specifically, this demo shows the first ten cateogries from ASPFAQs.com in the tabs on the left. Clicking on a tab will display the category's associated FAQs, with links to the FAQs. This demo displays parent/child data using a technique discussed in this article: An Extensive Examination of DataGrids: Part 14.

Note: the output of this code is suboptimal in browsers other than Internet Explorer. I am working to fix this....


Application Object
Arrays
ASP.NET
Cookies
Databases, Errors
Databases, General
Databases, Queries
Dates and Times
Email
FileSystemObject


Source Code

<%@ Page Language="VB" %>
<%@ Import Namespace = "System.Data" %>
<%@ Import Namespace = "System.Data.SQLClient" %>
<script runat="server">
    Private totalCount as Integer

	Sub Page_Load(sender As Object, e As EventArgs)
	  GetFAQCategories()  
	End Sub

	Sub GetFAQCategories()
	    Dim strSQL as String 
	    strSQL = "SELECT TOP 10 FAQCategoryID, Name FROM tblFAQCategory ORDER BY Name"

	    Dim myConnection as New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))
	    Dim myCommand as SqlCommand = New SqlCommand(strSQL, myConnection) 
	        
	    myConnection.Open()
	    rptTabInterface.DataSource = myCommand.ExecuteReader()
	    rptTabInterface.DataBind()
	    myConnection.Close()
	    
	    totalCount = rptTabInterface.Items.Count
	End Sub

	Function GetFAQsByCategory(catID as Integer) as DataTable
	    Dim strSQL as String 
	    strSQL = "SELECT FAQID, Description FROM tblFAQ WHERE FAQCategoryID = @CatID ORDER BY Description"

	    Dim myConnection as New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))
	    Dim myCommand as SqlCommand = New SqlCommand(strSQL, myConnection) 
	    myCommand.Parameters.Add(New SqlParameter("@CatID", catID))
	    
	    Dim myAdapter as New SqlDataAdapter(myCommand)
	    Dim dt as New DataTable
	    myConnection.Open()
	    myAdapter.Fill(dt)
	    myConnection.Close()
	    
	    Return dt
	End Function
</script>

  
  <script language="JavaScript">
    var lastSelectedNum = -1;
    var totalCount = <%=totalCount%>;
    
    function showTopic(num)
    {
      if (lastSelectedNum >= 0)
      {
        // reset the last selected item 
        var lastHeader = document.getElementById('h' + lastSelectedNum);
        var lastDetails = document.getElementById('d' + lastSelectedNum);
        
        lastHeader.style.backgroundColor = '#aaaaaa';
        lastHeader.style.borderRightStyle = 'solid';
        lastDetails.style.display = 'none';
      }       
       
      var header = document.getElementById('h' + num);
      var details = document.getElementById('d' + num);
      
      header.style.backgroundColor = '#eeeeee';
      header.style.borderRightStyle = 'none';
      details.style.display = 'inline';
      
      lastSelectedNum = num;
    }
    
    function setInitialPositions()
    {
      var topHeader = document.getElementById('h0');
      var container = document.getElementById('container');

      var maxHeight = -1;
      
      // set the top tab's top border
      topHeader.style.borderTopStyle = 'solid';
      topHeader.style.borderTopColor = 'black';
      topHeader.style.borderTopWidth = '1px';

      for (var i = 0; i < totalCount; i++)
      {
        var details = document.getElementById('d' + i);
        details.style.top = getAscendingTops(container);
        details.style.left = getAscendingLefts(container) + topHeader.clientWidth + 1;
        details.style.height = '100%';
        
		// determine the maximum heighted details pane, if needed
		if (!container.height)
		{        
          details.style.display = 'inline';
          if (details.clientHeight > maxHeight) maxHeight = details.clientHeight;
          details.style.display = 'none';
        }
      }     
      
      // see if we have an explicit height specified - if not, choose the largest details height
      if (!container.height)
      {
        container.style.height = maxHeight + 5;
      }
    }
    
    function getAscendingTops(elem){
	  if (elem==null)
		return 0;
	  else {
		return elem.offsetTop+getAscendingTops(elem.offsetParent);
	  }
    }

    function getAscendingLefts(elem){
	  if (elem==null)
		return 0;
	  else
	  {
	  	return elem.offsetLeft+getAscendingLefts(elem.offsetParent);
	  }
    }
  </script>

<asp:Repeater runat="server" id="rptTabInterface">
  <HeaderTemplate>
    <div id="container" style="width:100%;height:350px">
  </HeaderTemplate>
  
  <ItemTemplate>
    <div id='h<%# DataBinder.Eval(Container, "ItemIndex")%>' 
         onclick='showTopic(<%# DataBinder.Eval(Container, "ItemIndex")%>);' 
         style="cursor:pointer;cursor:hand;position:relative;z-index:2;border-left: solid 1px black;width:20%;background-color:#aaaaaa;border-right: solid 1px black;border-bottom: solid 1px black;padding:5px;">
      <%# DataBinder.Eval(Container.DataItem, "Name") %>
    </div>
  
    <div id='d<%# DataBinder.Eval(Container, "ItemIndex")%>'  style="overflow:auto;z-index:1;border: solid 1px black;width:80%;position:absolute;background-color:#eeeeee;padding:5px;display:none;">
      <asp:Repeater id="rptFAQsByCategory" runat="server"
                    DataSource='<%# GetFAQsByCategory(DataBinder.Eval(Container.DataItem, "FAQCategoryID")) %>'>
          <HeaderTemplate><ul></HeaderTemplate>
          <ItemTemplate>
            <li><a href='http://aspfaqs.com/aspfaqs/ShowFAQ.asp?FAQID=<%# DataBinder.Eval(Container.DataItem, "FAQID") %>'>
                   <%# DataBinder.Eval(Container.DataItem, "Description") %>
                </a></li>
          </ItemTemplate>
          <FooterTemplate></ul></FooterTemplate>
      </asp:Repeater>
    </div>
  </ItemTemplate>
  
  <FooterTemplate>
    </div>
  </FooterTemplate>
</asp:Repeater>

  <script language="JavaScript">
    setInitialPositions();
    showTopic(0);
  </script>


[Return to the article...]