In the Pioneer Cycling store, we used filtering to allow the user to limit the types of parts that are displayed on category_parts.jsp. The filtering functionality allows the user to filter parts by manufacturer, by frame types that the parts should fit, and by the part’s general price category.

Filtering functionality is composed of three pieces:

The Filtering Page

The filtering page initializes the PartsFilterFormHandler with filtering criteria including a list of manufacturers, types of frames the parts fit, and general price categories for the parts.

filtering.jsp:

<dsp:importbean bean="/atg/commerce/catalog/FilterCreator"/>
<dsp:importbean bean="/atg/commerce/catalog/RepositoryValues"/>
<dsp:importbean bean="/atg/dynamo/droplet/ForEach"/>

<dsp:include page="../common/HeadBody.jsp" flush="true"></dsp:include>

<dsp:include page="../common/StoreBrand.jsp" flush="true"></dsp:include>

<dsp:include page="../catalog/common/breadcrumbs.jsp" flush="true">
<dsp:param name="displaybreadcrumbs" value="true"/>
<dsp:param name="no_new_crumb" value="true"/></dsp:include>
</span>
<p>

<span class=storebig>Shop by Filtering</span><br>
<span class=help>Filtering allows you to see only parts in the catalog
      that meet the criteria that you indicate here.</span>

<p>
<dsp:form action="../catalog/category_parts.jsp" method="POST">

<table width=100% cellpadding=0 cellspacing=0 border=0>
 <tr>
  <td colspan=3 class=box-top-store>Filter Catalog</td>
 </tr>

 <tr valign=top><td class=box>
  <dsp:input bean="FilterCreator.searchAllManufacturers" type="radio"
     value="true"/>
   Show products from all manufacturers<br>
  <dsp:input bean="FilterCreator.searchAllManufacturers" type="radio"
     value="false"/>
   Show products from only these manufacturers<br>
  <dsp:select multiple="<%=true%>" bean="FilterCreator.manufacturers"
     size="4">
   <dsp:droplet name="RepositoryValues">
    <dsp:param name="itemDescriptorName" value="product"/>
    <dsp:param name="propertyName" value="manufacturer"/>
    <dsp:oparam name="output">
     <dsp:droplet name="ForEach">
      <dsp:param name="array" param="values"/>
      <dsp:param name="sortProperties" value="+id"/>
      <dsp:oparam name="output">
       <dsp:getvalueof id="option76" param="element.id"
          idtype="java.lang.String">
<dsp:option value="<%=option76%>"/>
</dsp:getvalueof><dsp:valueof param="element.id"/>
      </dsp:oparam>
     </dsp:droplet>
    </dsp:oparam>
   </dsp:droplet>
  </dsp:select>
  <p>

  <dsp:input bean="FilterCreator.anyFrame" type="radio" value="true"/>
   Show products that fit any frame<br>
  <dsp:input bean="FilterCreator.anyFrame" type="radio" value="false"/>
   Show only products that fit this frame<br>
  <dsp:select bean="FilterCreator.frameType">
   <dsp:droplet name="RepositoryValues">
    <dsp:param name="itemDescriptorName" value="frame-product"/>
    <dsp:param name="propertyName" value="frameType"/>
    <dsp:oparam name="output">
     <dsp:droplet name="ForEach">
      <dsp:param name="array" param="values"/>
      <dsp:oparam name="output">
       <dsp:getvalueof id="option116" param="element"
            idtype="java.lang.String">
<dsp:option value="<%=option116%>"/>
</dsp:getvalueof><dsp:valueof param="element"/>
      </dsp:oparam>
     </dsp:droplet>
    </dsp:oparam>
   </dsp:droplet>
  </dsp:select>
  <br>&nbsp;<br>
  </td>

  <td class=box>&nbsp;&nbsp;</td>

  <td class=box>
   <dsp:input bean="FilterCreator.priceSelectionType" type="radio"
              value="allPrices"/>
    Show products of all prices<br>
   <dsp:input bean="FilterCreator.priceSelectionType" type="radio"
        value="priceCategory"/>
    Show products that are priced<br>
   <dsp:select bean="FilterCreator.priceCategory" size="4">
    <dsp:droplet name="RepositoryValues">
     <dsp:param name="itemDescriptorName" value="product"/>
     <dsp:param name="propertyName" value="priceRange"/>
     <dsp:oparam name="output">
      <dsp:droplet name="ForEach">
       <dsp:param name="array" param="values"/>
       <dsp:oparam name="output">
        <dsp:getvalueof id="option166" param="element"
             idtype="java.lang.String">
<dsp:option value="<%=option166%>"/>
</dsp:getvalueof><dsp:valueof param="element"/>
       </dsp:oparam>
      </dsp:droplet>
     </dsp:oparam>
    </dsp:droplet>
   </dsp:select>
   <br>
   <P>

   <%/* Set these hidden params to cause the action to return to the
      * previous page */%>
   <input name="navCount" type="hidden" value='<dsp:valueof
               bean="/atg/commerce/catalog/CatalogNavHistory.navCount"/>'>
   <input type="hidden" name="navAction" value="jump">
   <input type="hidden" name="id" value="cat10005">

   <dsp:input bean="FilterCreator.submit" type="submit" value="  Filter
                    Catalog "/>
  </td>
 </tr>
</table>

<p>

</dsp:form>

</td>
</tr>
</table>

<p>

<dsp:include page="../common/StoreFooter.jsp" flush="true"></dsp:include>
<dsp:include page="../common/Copyright.jsp" flush="true"></dsp:include>

</BODY>
</HTML>

filtering.jsp imports and uses two Nucleus components, FilterCreator and RepositoryValues. The RepositoryValues configuration file sets a single property, the catalog for which products will be filtered.

RepositoryValues component:

$class=atg.repository.servlet.PossibleValues
repository^=CatalogTools.catalog

The FilterCreator component configures the PartsFilterFormHandler class’s repository property with the store catalog and sets the itemDescriptor to product, since parts are products.

FilterCreator component

$class=atg.projects.b2cstore.PartsFilterFormHandler
$scope=session
loggingIdentifier=Parts Filter Form Handler
repository^=CatalogTools.catalog
itemDescriptor=product

The PartsFilterFormHandler

The PartsFilterFormHandler accepts manufacturer names, frame types, and price categories and generates an atg.targeting.RuleBasedRepositoryItemGroup, which is a targeting rule set made up of SGML Content Targeting Rules.

The PartsFilterFormHandler overrides the getRuleRepresentation() methods of its parent class. This allows it to specify an SGML targeting rule.

Generating the Targeting Rules

The targeting rules are SGML rules that specify logical operations such as “and”, “or”, or “includes” to accept or reject repository items. See the Creating Rules for Targeting Content chapter of the ATG Personalization Programming Guide for more information on targeting rules.

If no filtering criteria have been entered by the user, getRuleRepresentation() returns a rule that accepts all items:

<ruleset>
  <accepts>
    <rule op=any>
    </rule>
  </accepts>
</ruleset>

When one or more conditions are specified via filtering.jsp, the PartsFilterFormHandler generates an “and” rule within the <accepts> rule that contains one or more child rules that specify the actual filtering criteria:

<ruleset>
  <accepts>
    <rule op=and>
      <rule op=isoneof>
        <valueof target="manufacturer.id">
        <valueof constant="[BatGoose, DZ Supply]">
      </rule>
      <rule op=eq>
        <valueof target="priceRange">
        <valueof constant="EXPENSIVE">
      </rule>
    </rule>
  </accepts>
</ruleset>

The top level <rule op=and> tag within the <accepts> tag is necessary because the filtering conditions must be grouped together with an “and” rule. In the above case, the manufacturer.id should be one of the listed constants and the price range should equal EXPENSIVE. Without the parent “and” rule, the filtering conditions are grouped together with an “or” rule.

Creating the RuleBasedRepositoryItemGroup

The RuleBasedRepositoryItemGroup is a Java Targeting object created from the SGML rules that were generated by the PartsFilterFormHandler. It is later used by the RuleBasedRepositoryItemGroupFilter to filter an array of parts repository items.

We created the RuleBasedRepositoryItemGroup within FilterFormHandler. Within its handleSubmit() method, the parent class, FilterFormHandler, retrieves the SGML rules from PartsFilterFormHandler via the overridden getRuleRepresentation() method and generates a RuleBasedRepositoryItemGroup object from those rules. The RuleBasedRepositoryItemGroup object is available via the getRepositoryItemGroup() method of the FilterFormHandler or, in JSP, via the repositoryItemGroup property.

You can duplicate the functionality of FilterFormHandler in your own code. The handleSubmit() method of FilterFormHandler simply calls the TargeterUtils.createGroup() method to create the RuleBasedRepositoryItemGroup.

Filtering and Displaying Parts Repository Items

The RuleBasedRepositoryItemGroupFilter component takes the RepositoryItemGroup created by FilterCreator and an array of repository items and outputs a subset of the input array that contains only those repository items that pass the filter.

ProductsLineItem.jsp Fragment
<dsp:importbean bean="/atg/dynamo/droplet/ForEach"/>
<dsp:importbean bean="/atg/commerce/catalog/FilterCreator"/>
<dsp:importbean bean="/atg/targeting/RuleBasedRepositoryItemGroupFilter"/>

<declareparam name="array" class="java.lang.Object[]"
       description="An array of repository items">

<%/* Filter the array of repository items in the page param, "array" */%>
<dsp:droplet name="RuleBasedRepositoryItemGroupFilter">
 <dsp:param name="inputItems" param="array"/>
 <dsp:param bean="FilterCreator.repositoryItemGroup" name="repositoryItemGroup"/>
 <dsp:oparam name="output">

  <%/* Display each filtered item */%>

  <dsp:droplet name="ForEach">
   <dsp:param name="array" param="filteredItems"/>
   <dsp:param name="elementName" value="childProduct"/>
   <dsp:oparam name="outputStart">
    <table cellspacing=3 cellpadding=0 border=0>
   </dsp:oparam>
   <dsp:oparam name="output">
    <tr valign=top>
     <td>
      <dsp:valueof param="childProduct.manufacturer.displayName"/>
     </td>
     <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
     <td colspan=3>
      <b>
     <dsp:include page="../common/ItemLink.jsp" flush="true">
      <dsp:param name="Item" param="childProduct"/>
      <dsp:param name="Image" param="childProduct.thumbnailImage"/>
      <dsp:param name="DisplayText" param="childProduct.displayName"/>
      <dsp:param name="navAction" value="push"/>
     </dsp:include>
      </b>
     </td>
    </tr>

   <%/* List all child SKUs of the product */%>
    <dsp:droplet name="ForEach">
     <dsp:param name="array" param="childProduct.childSKUs"/>
     <dsp:param name="elementName" value="childSku"/>
     <dsp:oparam name="output">
      <tr valign=top>
       <td colspan=2></td>
       <td>
        <dsp:valueof param="childSku.displayName"/>
       </td>
       <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
       <td align=right>
      <dsp:include page="../common/DisplaySkuPrice.jsp" flush="true">
     <dsp:param name="Sku" param="childSku"/>
     <dsp:param name="Image" param="childSku.thumbnailImage"/>
     <dsp:param name="navAction" value="push"/>
     <dsp:param name="DisplayText" param="childSku.displayName"/>
      </dsp:include>
       </td>
      </tr>
     </dsp:oparam>
    </dsp:droplet>
    <tr>
     <td colspan=5><hr size=0></td>
    </tr>
   </dsp:oparam>
   <dsp:oparam name="outputEnd">
    </table>
   </dsp:oparam>
  </dsp:droplet>
 </dsp:oparam>
</dsp:droplet>

The ProductsLineItem.jsp fragment imports the FilterCreator component to access the parts RuleBasedRepositoryItemGroup from its repositoryItemGroup property, and imports the RuleBasedRepositoryItemGroupFilter servlet bean in order to apply the RuleBasedRepositoryItemGroup to each repository item. ProductsLineItem.jsp also declares a page parameter called array that is set by the caller to the array of parts repository items to display. All the actual filtering work is done up front in the first invocation, RuleBasedRepositoryItemGroupFilter. As parameters, the array that’s been passed to this page fragment is passed on to the inputItems parameter in the filter servlet bean, and the RuleBasedRepositoryItemGroup created by the PartsFilterFormHandler (described above) is passed in as the repositoryItemGroup parameter. In the output open parameter, the ForEach servlet bean iterates the RuleBasedRepositoryItemGroupFilter's output parameter filteredItems that contains the list of repository items that have passed the filter.

 
loading table of contents...