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">
       &nbsp; &nbsp;
   <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>
 
loading table of contents...