Spry Dynamic Tabs 2

A reader recently asked about my Spry Panel with Dynamic Content post:

How do I extend it to automatically generate each TAB from an external file as well.

The tabs are generated from [an] external XML data (the XML contains the link to be run when the Tab is clicked), and then each tab generates it's content when it is clicked.

In my post the tabs were hard coded, to dynamically generate the tabs using an xml file and then dynamically load the content specified in the xml file it's just a little bit more work (but less typing!).

I started out with a simple xml file that looks like:

<?xml version="1.0" encoding="UTF-8"?>
<tabs>
   <tab>
      <title>Tab1</title>
      <url>examples/tab1.html</url>
   </tab>
   <tab>
      <title>Tab2</title>
      <url>examples/tab2.html</url>
   </tab>
</tabs>

A simple enough structure that has the title of the tab and a URL which will ultimately be used to populate the tab.

We need to set up the appropriate links to the required css and Javascript files that will make it all work.

<link href="../assets/css/SpryTabbedPanels.css" rel="stylesheet" type="text/css" />
   <script language="JavaScript" type="text/javascript" src="../assets/js/xpath.js"></script>
   <script language="JavaScript" type="text/javascript" src="../assets/js/SpryData.js"></script>
   <script language="JavaScript" type="text/javascript" src="../assets/js/SpryTabbedPanels.js"></script>

The Code

The HTML in this case is a little bit different because we will be generating the tabs dynamically from the xml data, but it will also be a heck of a lot shorter.

<script type="text/javascript">
//set up our dataset
var dsTabs = new Spry.Data.XMLDataSet("data/data.xml", "tabs/tab");
//function to dynamically load the contents of a url into the specified tab
function loadContent(panel,url){
   Spry.Utils.updateContent(panel,url);
}
//observer set to run after the data is loaded to populate the first tab.
Spry.Data.Region.addObserver("example1Region",dateLoadedCallback);
function dateLoadedCallback(notificationType, notifier, data)
{
   if (notificationType =="onPostUpdate"){   
       row= dsTabs.getRowByRowNumber(0)
       if(row){
       loadContent('0',row.url)
       }
}
}
</script>

   <div id="example1Region" spry:region="dsTabs">
   <div id="dynamicTabs" class="TabbedPanels">
      <ul class="TabbedPanelsTabGroup">
         <li spry:repeat="dsTabs" class="TabbedPanelsTab" onclick="loadContent('{ds_RowID}','{url}');" tabindex="0">{title}</li>
      </ul>
      <div class="TabbedPanelsContentGroup">
         <div spry:repeat="dsTabs" id="{ds_RowID}" class="TabbedPanelsContent"></div>
      </div>
   </div>
      <script type="text/javascript">
      var t1 = new Spry.Widget.TabbedPanels("dynamicTabs");
   </script>
</div>
The big change here is the addition of the spry:repeat="dsTabs" attribute. This tells spry to create an element for every entry in the data set. Basically an automated loop through every record. We do this twice once for the tabs (TabbedPanelsTab) and once for the tab panels (TabbedPanelsContent). Also in order for us to dynamically load the content into our dynamically created records I use an internal spry dataset row id ds_RowId as the unique id for each tab. This lets me set up an onclick event on each tab.

On the Tab

onclick="loadContent('{ds_RowID}','{url}');"

On the tab Content:

<div spry:repeat="dsTabs" id="{ds_RowID}" class="TabbedPanelsContent">

The loadContent javascript function is responsible for loading the content from the external file specified by our binding.

function loadContent(panel,url){
   Spry.Utils.updateContent(panel,url);
}

And then lastly I set up an Observer function to fire after the data is loaded. Since we didn't set which tab to have open by default it is the 1st tab (tab zero). Without the observer function our tab would initially be empty.

Spry.Data.Region.addObserver("example1Region",dateLoadedCallback);
function dateLoadedCallback(notificationType, notifier, data)
{
   if (notificationType =="onPostUpdate"){   
       row= dsTabs.getRowByRowNumber(0,true)
       if(row){
       loadContent('0',row.url)
       }
}
}

Note that this is not the most efficient method of defining an observer you can also do it all in one line like below but for clarity sake I have it broken out.

Spry.Data.Region.addObserver("example1Region",
   {onPostUpdate: function(ds,data)
      {row= dsTabs.getRowByRowNumber(0)
       if(row){
         loadContent('0',row.url)
       }
      }
   });

Summary

As with most of the Spry API a little Javascript goes a long way. In this example we used a hard coded xml file but we could easily change our dataset to use xml generated dynamically by a ColdFusion component or another server-side language, which in turn could contain a URL to another server-side page which would dynamically generate our contents.

Happy Coding...

Related Blog Entries

Comments
Staca's Gravatar Hello and thank you for this Tuto !
I m newbie with the spry adobe
One question, i ' m tried to give dynamic Accordion like this Tabbed.
Could you explain how to do like this Tabbed ?
Thank you
# Posted By Staca | 3/14/08 8:07 AM