YUI TabView with nested ASP.Net Repeater Control on Client Side

23. July 2010 09:42

According to the YUI docs and YUI Developer Pages, a YUI TabView control is able to create a tabview through existing HTML or "entirely through javascript."  After scouring the web in vain, I realized that there were no resources anywhere that addressed what happens when you need to create the YUI TabView dynamically with the content being generated through a .Net Repeater control.  I know this probably sounds trivial to some, but here's the scenario:

YUI TabView creates the actual tab buttons through the following syntax:



 var tabbs = new YAHOO.widget.TabView('tabViewWrapper')
tabbs.addTab(new YAHOO.widget.Tab({
label:'Tab One Label',
content:'<p>Tab One Content</p>',
active:true
}));

YAHOO.util.Event.onContentReady("tabViewWrapper", initTabView); </script>
...etc

Both of these methods work independently, but what happens if you have ASP.Net repeater controls that is creating content at runtime. Well, I'll save you some time. It doesn't work... at least it doesn't work simply.  Check this example:

<div id="tabViewWrapper">
     <ul id="tabNav" class="yui-nav">
     </ul>

     <div id="yui-content" class="yui-content">
          <asp:Repeater id="rptData" runat='server' OnItemDataBound="rptData_ItemDataBound">
              <ItemTemplate>

                  <div id="something" >
                      <%=Eval("SomeProperty")%>
                  </div>
              </ItemTemplate>
          </asp:Repeater>
     </div>
</div>



See the problem yet?  I'll save you the suspense.  The Repeater is inside of the content section, but the <ul> for the tabview buttons is outside of the content section and there is no way to reach into the current repeater item to try to bind to a property when the <ul> section is out of scope.  Furthermore, to make things even more complicated, you must consider what would happen if the repeater was only PART of your tabview content and you had something static inside the yui-content section that was not being generated from the repeater.  I'm sure you can imagine that you can quickly end up between a rock and a hard place.  In order for YUI TabView to activate, there has to be an item set with the class="selected" and without doing a bunch of server-side processing... it would be tough to figure out which item in the repeater loop needs to be set as first, not to mention that the <li> doesn't even exist yet.

So check this out, what I realy want is to avoid server-side processing by creating the YUI tabview on the client.  Afterall, it is a visual element and you shouldn't have to recompile your application to make a visual change.  In addition, neither of the two methods above really provide a clean solution.  If you create the content without the <li>, it doesn't work.  If you create the <li> without the content, YUI fails.  I can't imagine anyone would want to pass a gigantic innerHTML string to a javascript function to try to create the tab with the

tabbs.addTab(new YAHOO.widget.Tab({label:'Tab One Label',
content:'<p>Tab One Content</p>'});



method. Pain in the ass.  You can't create your TabView until you have both the header and the content, you can't pass your content until your inner nested repeater has executed, your <ul> is out of scope for the repeater... etc etc

So here's what I did. Create the following javascript function:

<script type="text/javascript" language="javascript">
     function createTabTitle(val){
          var tabNav = document.getElementById("tabNav");
          var anchorTag = document.createElement('a');
          anchorTag.setAttribute('href', 'javascript:void(0)');
          var emTag = document.createElement('em');
          emTag.appendChild(document.createTextNode(val));
          anchorTag.appendChild(emTag);
          var newLi = document.createElement('li');
          newLi.appendChild(anchorTag);
          tabNav.appendchild(newLi);
     }
</script>

Now you have a javascript function that can be called on every iteration of the repeater and pass the value from the <%#Eval('')%> command as a string into the javascript.  In essence, you are fooling YUI because you dont actually turn "on" the tabview until all of the tabViewWrapper content is ready for use, and by that point, you have all of your <li> tags safely in place, in order, and ready to go.  Once YAHOO.util.Event.onContentReady fires, the pages will be complete and ready to be connected to YUI as if you had written static <li> tags from the beginning... except you haven't.  You now can create a YUI TabView completely dynamically without involving server-side javascript.
Hope this helped.



Here is a complete source example;

<html><head>
<link rel="stylesheet" src="tabview.css"/>
<script type="text/javascript" language="javascript" src="yui/yahoo-min.js"></script> 
<head><script type="text/javascript" language="javascript" src="yui/yahoo-dom-event/yahoo.dom.event.js"></script>
<script type="text/javascript" language="javascript" src="yui/element/element-min.js"></script>
<script type="text/javascript" language="javascript" src="yui/connection/connection-min.js"></script>
<script type="text/javascript" language="javascript" src="yui/tabview/tabview-min.js"></script>

<script type="text/javascript" language="javascript">
     var myTabs;

     function initTabView(){
           myTabs = new YAHOO.widget.TabView("tabViewWrapper");
           myTabs.set('activeIndex', 0); //We can do this now cause everything is already on the page
     }

     function createTabTitles(val){
          var tabNav = document.getElementById("tabNavList");
          var anchorTag = document.createElement('a');
          var emTag = document.createElement('em');
          var liTag = document.createElement('li');
          emTag.appendChild(document.createTextNode(val));
          anchorTag.setAttribute('href', 'javascript:void(0));
          anchorTag.appendChild(emTag);
          liTag.appendChild(anchorTag);
          tabNav.appendChild(liTag);
     }
</script>  </head>

<body>

<div id="tabViewWrapper">
     <ul id="tabNav" class="yui-nav"></ul>
     <asp:Repeater runat="server" id="whatever" > //This is going to create our outer section
          <ItemTemplate>
               <script type="text/javascript" language="javascript"> createTabTitle(<%#Eval("DisplayNameFromRepeater")%>
               <div>
                  ...some other content here
                  <asp:Repeater id="nestdRepeater" runat="server">...</asp:Repeater>
               </div>
          </ItemTemplate>
     </asp:Repeater>
</div>
</body>
</html>

Ok so there you go.  Hope this helped.

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Log in