Hierarchical Navigation
To make it easy to browse the product catalog in the Pioneer Cycling site, we organized the product catalog into a hierarchy of categories, with several levels of subcategories and products. To impose this hierarchy, we defined properties of category called childProducts
and childCategories
that are lists of categories or products as appropriate. There is no limit to the number of places that a single item (product or category) can appear as a child.
Navigation down the hierarchy in any category can be shown in a Java Server Page by rendering a link to each of the childProducts
and childCategories
. There are many ways to use the hierarchy to display the content in the catalog. This manual describes one way to navigate.
On the parts category page of Pioneer Cycling that shows bike parts, the left panel contains a display of all the categories of parts and their subcategories, using an iterative approach. This implementation requires knowing the depth of the tree, or at least knowing how deep you want to traverse. We used the JSP snippet below, CategoryTreeTwoLevel.jsp
, to generate the content of the panel. It retrieves the parts category with the CategoryLookup
component. The itemId
parameter required by CategoryLookup
is supplied by the Java Server Page that invokes this fragment. Then, a ForEach
component renders a link to each of the childCategories
of parts. For each child category of parts, a nested ForEach
component renders a link to each of its child categories.
<dsp:droplet name="/atg/commerce/catalog/CategoryLookup"> <dsp:param bean="/atg/dynamo/servlet/RequestLocale.locale" name="repositoryKey"/> <dsp:oparam name="output"> <dsp:droplet name="/atg/dynamo/droplet/ForEach"> <dsp:param name="array" param="element.childCategories"/> <dsp:param name="elementName" value="child"/> <dsp:param bean="/OriginatingRequest.requestLocale.locale" name="repositoryKey"/> <dsp:oparam name="output"> <dsp:include page="../common/ItemLink.jsp" flush="true"> <dsp:param name="Item" param="child"/> <dsp:param name="navAction" value="jump"/> <dsp:param name="Image" param="child.thumbnailImage"/> <dsp:param name="DisplayText" param="child.displayName"/> </dsp:include> <br> <dsp:droplet name="/atg/dynamo/droplet/ForEach"> <dsp:param name="array" param="child.childCategories"/> <dsp:param name="elementName" value="grandChild"/> <dsp:oparam name="output"> <dsp:include page="../common/ItemLink.jsp" flush="true"> <dsp:param name="Item" param="grandChild"/> <dsp:param name="navAction" value="jump"/> <dsp:param name="Image" param="grandChild.thumbnailImage"/> <dsp:param name="DisplayText" param="grandChild.displayName"/> </dsp:include> <br> </dsp:oparam> </dsp:droplet> </dsp:oparam> </dsp:droplet> </dsp:oparam> </dsp:droplet>
You could also use a recursive algorithm to display the whole tree. The JSP code sample below retrieves the category on the top-most level with the CategoryLookup
component and invokes itself to recurse through the child categories. A category ID is passed in as the ID parameter in the URL. The major drawback of this implementation is that if your tree has any circular references (for example, a category containing an ancestor category as a child category), it will recurse forever.
<dsp:importbean bean="/atg/dynamo/droplet/ForEach"/> <dsp:importbean bean="/atg/commerce/catalog/CategoryLookup"/> <!-- display all products under this category and subcategories. -- the id parameter specifies the repository id of the top-most -- category. --> <dsp:droplet name="CategoryLookup"> <dsp:param bean="/OriginatingRequest.requestLocale.locale" name="repositoryKey"/> <dsp:param name="id" param="id"/> <dsp:oparam name="output"> <!-- display a link to each product in a category --> <!-- the param element is a Category object passed in to this droplet --> <dsp:droplet name="ForEach"> <dsp:param name="array" param="element.childProducts"/> <dsp:oparam name="output"> <dsp:getvalueof id="templateUrl" param="element.template.url" idtype="java.lang.String"> <dsp:a href="<%=templateUrl%>"><dsp:valueof param="element.displayName"/></dsp:a> </dsp:getvalueof><br> </dsp:oparam> </dsp:droplet> <!-- recursively call this droplet to display products for all childCategories --> <dsp:droplet name="ForEach"> <dsp:param name="array" param="element.childCategories"/> <dsp:oparam name="output"> <dsp:getvalueof id="repId" param="element.repositoryId"> <dsp:include page="test.jsp" flush="true"> <dsp:param name="id" value="<%=repId%>"/> </dsp:include> </dsp:getvalueof> </dsp:oparam> </dsp:droplet> </dsp:oparam> </dsp:droplet>