Filtering Nodes in an ADF Faces Tree Component

This post describes a method to filter nodes in an ADF Faces Tree. You can download the sample application from here. The application is developed in JDeveloper 10.1.3.2.0 and requires a connection to the HR schema.

Sample Application

In the sample application, Regions are the root nodes of the tree. Countries appear as child nodes under the Region they belong.

Each Region node in the tree has an inputText component. The value entered into the inputText is used to filter the countries in the Region.

Building the Sample Application

Please refer to the post “ADF Faces Tree Example” in this blog for more information on how to build a JSF page with an ADF Faces Tree Component.

Once you create your page with the tree component follow the steps below to implement the filter functionality.

  • Create a HashMap object and its accessor methods in the ApplicationModuleImpl class. This object is going to store the Region-Filter Value pairs entered by the user.

private HashMap filters = new HashMap();

public void setFilters(HashMap filters)
{
this.filters = filters;
}

public HashMap getFilters()
{
return filters;
}
  • Override the executeQueryForCollection method of the CountriesView;

protected void executeQueryForCollection(Object qc, Object[] params, int i)
{
HashMap fMap = ((AppModuleImpl)getApplicationModule()).getFilters();
QueryCollection queryCol = (QueryCollection)qc;
Object[] values = queryCol.getRowFilter().getParamValues();
String filter = (String)fMap.get(values[0].toString());
if (filter == null)
this.setWhereClause(null);
else
this.setWhereClause("upper(country_name) like upper('%" + filter + "%')");
super.executeQueryForCollection(qc, params, i);
}
  • Create a request scope bean named TreeBean

package com.gerger.view;

import com.gerger.model.AppModuleImpl;
import javax.faces.context.FacesContext;
import oracle.adf.view.faces.component.core.data.CoreTree;
import oracle.adf.view.faces.component.core.input.CoreInputText;
import oracle.adf.view.faces.event.DisclosureEvent;
import oracle.jbo.ApplicationModule;
import oracle.jbo.domain.Number;
import oracle.jbo.uicli.binding.JUCtrlHierNodeBinding;
import oracle.jbo.uicli.binding.JUFormBinding;

public class TreeBean
{

private CoreInputText treeFilter;

public TreeBean()
{
}

public void treeDisclosureListener(DisclosureEvent disclosureEvent)
{
CoreTree tree = (CoreTree)disclosureEvent.getComponent();
int rowIndex = tree.getRowIndex();
String attrName = ((JUCtrlHierNodeBinding)tree.getRowData(rowIndex)).getAttributeNames()[1];
if (attrName.equals("RegionName"))
{
String filterValue = (String)getTreeFilter().getValue();
Number regionId = (Number)((JUCtrlHierNodeBinding)tree.getRowData(rowIndex))
.getAttribute("RegionId");
((AppModuleImpl)getAppModule()).getFilters().put(regionId.toString(), filterValue);
}
}

public void setTreeFilter(CoreInputText treeFilter)
{
this.treeFilter = treeFilter;
}

public CoreInputText getTreeFilter()
{
return treeFilter;
}

public ApplicationModule getAppModule()
{
FacesContext fctx = FacesContext.getCurrentInstance();
ApplicationModule appModule = ((JUFormBinding) fctx.getApplication()
.createValueBinding("#{bindings}").getValue(fctx))
.findDataControl("AppModuleDataControl").getApplicationModule();
return appModule;
}

}

The treeDisclosureListener detects the expand/collapse events of the tree nodes. If the node that fired the event is a Region then the value in the inputText component is added to the HashMap object that stores Region-Filter Value pairs.

  • Modify the nodeStamp facet so that the tree nodes display the corresponding stamp for each region or city.

  • Add an inputText component to the nodeStamp facet of the tree.

Pressing the enter key while the cursor is in an inputText, applies the filter criteria to the child nodes of the active Region node and expands it. This is accomplished by executing the same JavasScript that runs when a tree node is expanded. Below the final text of the JSP page;

<%@ page contentType="text/html;charset=windows-1252"%><%@
taglib uri="http://java.sun.com/jsf/html" prefix="h"%><%@
taglib uri="http://java.sun.com/jsf/core" prefix="f"%><%@
taglib uri="http://xmlns.oracle.com/adf/faces" prefix="af"%><%@
taglib uri="http://xmlns.oracle.com/adf/faces/html" prefix="afh"%>
<f:view>
<afh:html>
<afh:head title="ADF - Filter For Af:Tree Component">
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1252"/>
<style type="text/css">
.in { width: 25px; border: 1px solid black; margin-left: 5px;
font-family: sans-serif;}
.h { font-weight: bold; }
</style>
<afh:script text="
function releaseFilter(e, obj)
{
var keynum = (window.event) ? window.event.keyCode : ((e.which) ? e.which : 0);
if (keynum == 13)
{
var objName = obj.name;
var index = objName.substring(objName.indexOf(':') + 1, objName.lastIndexOf(':'));
_adftreetree.treeState.action('show', index, obj);
return false;
}
}"/>
</afh:head>
<afh:body>
<af:messages/>
<af:form>
<af:tree value="#{bindings.RegionsView.treeModel}" var="node"
id="tree"
disclosureListener="#{myTreeBean.treeDisclosureListener}">
<f:facet name="nodeStamp">
<h:panelGrid columns="2" cellpadding="0" cellspacing="0">
<af:outputText value="#{node.RegionName}" styleClass="h"
rendered="#{node.RegionName != null}"/>
<af:outputText value="#{node.CountryName}"
rendered="#{node.RegionName == null}"/>
<af:inputText styleClass="in" maximumLength="3"
rendered="#{node.RegionName != null}"
onkeydown="releaseFilter(event, this);"
binding="#{myTreeBean.treeFilter}"/>
</h:panelGrid>
</f:facet>
</af:tree>
</af:form>
</afh:body>
</afh:html>
</f:view>

Comments

Popular posts from this blog

PostgreSQL for Oracle Developers and DBA's