14.3. DrilldownDrilldown, Menu, Progressive Figure 14-6. Drilldown14.3.1. Goal StoryPam is booking a trip on the corporate travel planner. She sees a form with the usual fields and clicks on location. Suddenly, a list of cities fades in beside the form, and Pam selects Paris. Beside the city list, a third list appears, this one showing approved hotels. Pam chooses the Hilton, and both lists disappear. The location field now contains "Paris Hilton" as Pam had intended. 14.3.2. ProblemHow can the user select an item in a hierarchical structure? 14.3.3. Forces
14.3.4. SolutionTo let the user locate an item within a hierarchy, provide a dynamic Drilldown. The Drilldown allows for navigation through a hierarchy and ultimately for an item to be chosen. At each level, there are several types of elements in the Drilldown:
In some hierarchies, items and categories are mutually exclusive: items only exist at the edgesor leavesof the hierarchy. Even when that's the case, items and categories should be distinguished for the sake of clarity. The upward navigator goes by different names, but a general guideline is that it should tell the user which category that she is going back to. Typical applications include navigating and filling out a field by drilling down a hierarchy of candidate items. As the user drills down the hierarchy, will you show each progressive level? There are three main options (Figure 14-7):
Figure 14-7. Drilldown stylesThe first two options are modeless; the third is modal. Modeless interaction works well with Ajax, where it's possible to dynamically update, without page refresh, the menu as well as any surrounding content related to the user's selection. Specifically:
14.3.5. Decisions14.3.5.1. Will you call on the server each time the user navigates through the Drilldown?Sometimes the entire hierarchy is loaded as a one-off event. Other times, categories can be pulled down as required using an XMLHttpRequest Call (Chapter 6). The choice is governed by two things:
14.3.6. Real-World Examples14.3.6.1. BetfairBetfair (http://betfair.com) uses a Drilldown to locate an event you wish to bet on (Figure 14-8). At the top level, the "All Markets" Drilldown contains various categories in alphabetical order, from "American Football" to "Special Bets" to "Volleyball." Clicking on "Special Bets" yields several countries, along with a "General" category, and you can continue to drill down to the list of bets. Clicking on one of those bets sets the main page content. "All Markets" is one of two Drilldowns. The other is "My Markets," a personalized Drilldown available to registered users. Figure 14-8. Betfair14.3.6.2. Backbase portalThe Backbase portal demo (http://projects.backbase.com/RUI/portal.html) contains several independent Portlets. Of interest here is the "local directory" Portlet, which is actually a Drilldown with top-level categories such as "education" and "health" drilling down to relevant links. 14.3.6.3. OpenRico accordian widgetThe OpenRico framework (http://openrico.org/rico/demos.page?demo=ricoAccordion.html) includes an accordian widget. Clicking on a category bar reveals the content. Because it lacks a deep hierarchy of categories, it's technically not a Drilldown, but it's a good solution when you do have a flat set of categories. 14.3.7. Code Refactoring: AjaxPatterns Drilldown Portal14.3.7.1. OverviewThe basic Portal Demo (http://ajaxify.com/run/portal) illustrates Multi-Stage Download (Chapter 13), showing how different content blocks can be downloaded in parallel. One of those is a block of links to Ajax resources. To keep the block small, only a few links are present. But is there any way we could keep the link block physically small while offering a large number of links? Of course there is . . . a Drilldown will occupy roughly the same space, yet with a little interaction, the user will be able to navigate through a large collection of links. The Drilldown Portal Demo (http://ajaxify.com/run/portal/drilldown) introduces a Drilldown. A Category can contain any combination of Categories and Links (Figure 14-9). For instance: The top-level category, "All Categories," contains only Categories, the "Websites" category contains just links, and the "Overviews" category contains some overviews as well as a subcategory, "Podcast Overviews" (Figure 14-10). Categories and links are rendered similarly, but not identically. Each category menu includes a link to the previous category level. Figure 14-9. Categories and Links: the Composite PatternFigure 14-10. Drilldown with Categories (Italicized) and LinksThe basic interaction sequence works like this:
On page load, the Drilldown is blank, and the browser requests information for the top-level category. The server response triggers the creation of a new Drilldown. 14.3.7.2. Browser-side implementationThe initial HTML just shows a blank div. The width is constrained because the Drilldown's parent container has a fixed width: <div >Loading ...</div> On page load, the top-level category is requested: retrieveCategory("All Categories"); Then begins the standard process of requesting a category with XMLHttpRequest, then rendering the menu accordingly. This occurs not only on page load, but every time the user clicks on a category within the drop-down. The server returns an XML file with category data.[*] The specification contains the name, the parent name, and a list of items. Each item is either a category or a link. Note that only the information for this level of the Drilldown is provided.
<category name="Overviews" parent="All Categories"> <items> <link> <url>http://en.wikipedia.org/wiki/AJAX</url> <name>Wikipedia Article</name> </link> <link> <url>http://www.adaptivepath.com/publications/essays/archives/000385.php </url> <name>First Ajax</name> </link> <category name="Podcast Overviews" parent="Overviews" /> </items> </category> The browser then parses this XML, using the standard DOM API, to produce HTML for the Drilldown. Links are shown as standard HTML anchor links; categories are Div elements. Event handlers ensure that when a category is clicked, including the "Back To (previous)" category, the browser will kick off another retrieve-and-render cycle: function onDrilldownResponse(xml) { var category = xml.getElementsByTagName("category")[0]; var html=""; var categoryName = category.getAttribute("name"); html+="<div id='categoryName'>" + categoryName + "</div>"; var parent = category.getAttribute("parent"); if (parent && parent.length > 0) { var parentName = category.getAttribute("parent"); html+="<div id='parent' onclick=\"retrieveCategory('" + parent + "')\"" + "'>Back to <br/>'" + parent + "'</div>"; } var items = category.getElementsByTagName("items")[0].childNodes; for (i=0; i<items.length; i++) { var item = items[i]; if (item.nodeName=="link") { var name = item.getElementsByTagName("name")[0].firstChild.nodeValue; var url = item.getElementsByTagName("url")[0].firstChild.nodeValue; html+="<div class='link'><a href='" + url + "'>" + name + "</a> </div>"; } else if (item.nodeName=="category") { var name = item.getAttribute("name"); html+="<div class='category' " + "onclick='retrieveCategory(\""+name+"\")'>"+name+" </div>"; } } $("drilldown").innerHTML = html; } 14.3.7.3. Server-Side ImplementationThe server-side implementation relies on the Composite pattern (see Gamma et al., 1995). A Category consists of further Category objects and also of Link objects. We rely on Category and Link having two common operations:
With these operations encapsulated in the Category and Link objects, the main script is quite small: require_once("Link.php"); require_once("Category.php"); require_once("categoryData.php"); header("Content-type: text/xml"); $categoryName = $_GET['categoryName']; $category = $topCategory->findItem($categoryName); if ($category) { echo $category->asXMLTag(true); } else { echo "No category called '$categoryName'"; } 14.3.7.4. Further refactoring: a Drilldown with dynamic contentIn the refactoring above, the top-level category, and all of the data underneath it, is hardcoded in categoryData.php. In fact, the hierarchy data could easily be generated on demand to create a Drilldown with dynamic content. In a further refactoring (http://ajaxify.com/run/portal/drilldown/syncLinks), a Cross-Domain Proxy (Chapter 10) is introduced to grab the actual results from the AjaxPatterns Wiki Links Page (http://ajaxpatterns.org/Ajax_Links). It's not a true Cross-Domain Proxy because instead of grabbing the results in real-time, a process runs to pull them every sixty seconds and store them locally, where they can be picked up by the Drilldown script. 14.3.8. Alternatives14.3.8.1. Live SearchDrilldown lets the user locate an item by browsing through a hierarchy. Live Search (see later) instead lets you locate an item by typing, and the data need not be hierarchical. 14.3.8.2. TreeLike a Drilldown, a Tree widget lets the user navigate a hierarchy, just like the tree of files and folders in desktop file managers. Tree widgets, even if they expand and collapse, tend to take up more space than Drilldowns, but the more detailed view can be useful for longer, more complex, tasks. 14.3.9. Related Patterns14.3.9.1. MicrolinkContent blocks, produced when particular categories or items are selected can be associated with the Drilldown. Thus, the Drilldown contents are being used as Microlinks (Chapter 15). 14.3.9.2. Browser-Side CacheIf each navigation event leads to a query of the server, consider retaining results in a Browser-Side Cache (Chapter 13). 14.3.9.3. PortletA Drilldown is usually a form of Portlet (Chapter 15). It has its own state, and the user can usually conduct a conversation with the Drilldown in isolation. |