Thursday Jan 17, 2013

How to create cascading (depending) auto suggest behavior using BC4J

In continuation to my previous blog on "How to create multi level cascading (dependent) list of values using BC4J", i am trying to leverage a similar usecase using af:autoSuggestBehavior in this article. Though the usecase looks same, the implementation is slightly different for this.

Let us assume a usecase where we have some text fields with auto suggest feature enabled, and their suggested items could be dependent on one other. For ex : Country, State and City.

This could be modeled by having an EO and VO created based on Person table and read-only look-up VOs created based on Country, State and City tables.

model.jpg

VOs.jpg

Implementing the dependency between LOVs is pretty straight forward. However, implementing the dependency between the auto suggest items is not. In order to achieve the dependency, first we would need couple of methods returning current row's CountryId and StateId. We could add them up in the AMImpl class.

public Number getCurrentCountryId(){
return (Number) this.getPersonView1().getCurrentRow().getAttribute("CountryId");
}

public Number getCurrentStateId(){
return (Number) this.getPersonView1().getCurrentRow().getAttribute("StateId");
}

As we need to filter out the States based on the Country and the City based on the Country & State, we would need to modify the query of these two VOs to include a bind variable in the where clause.

whereClause.jpg

For having the auto suggest, we need to have a view criteria defined for all the three look-up VOs (CountryView, StateView and CityView).

CountryVC.jpg

StateVC.jpg

CityVC.jpg

Generate VOImpl classes for Country, State and City VOs (with Include bind variable accessors option checked), and then expose setBindCountryName (in Country VO), setBindStateName (in State VO) and setBindCityName (in City VO) methods as client interfaces.

And the last part on the model is to pass the current row's CountryId and StateId to the Bind Variables defined in the State and City VOs. Also, we need to get the VCs created above to be executed by default (By editing the VO instance in the AM's data model), so that the auto suggest list would be filtered as and when the users type.

CountryViewAM.jpg

StateViewAM.jpg

CityViewAM.jpg

Here, we specify groovy expression for the CountryId and StateId as adf.object.applicationModule.<methodName>. For more information about using groovy expressions, check out this : http://www.oracle.com/technetwork/developer-tools/jdev/introduction-to-groovy-128837.pdf .

With this, we are done with setting up the model layer for the auto suggest dependency.

In the View layer, we would create an ADF Form based on the Person VO, with all the navigation buttons.

PersonJSPX.jpg

In order to construct the onSuggest items, we would create Tree Bindings for Country VO, State VO and City VO, along with method action bindings for the setBindCountryName, setBindStateName and setBindCityName methods.

pagedef.jpg

Now, we could add af:autoSuggestBehavior for CountryId, StateId and CityId fields. Then, add onSuggest methods in backing bean for populating the on suggest items for each fields.

onSuggest method for Country field :

public List onCountrySuggest(String searchCountryName) {
ArrayList<SelectItem> selectItems = new ArrayList<SelectItem>();

System.out.println(searchCountryName);
//get access to the binding context and binding container at runtime
BindingContext bctx = BindingContext.getCurrent();
BindingContainer bindings = bctx.getCurrentBindingsEntry();
//set the bind variable value that is used to filter the View Object
//query of the suggest list. The View Object instance has a View
//Criteria assigned
OperationBinding setVariable = (OperationBinding) bindings.get("setBind_CountryName");
setVariable.getParamsMap().put("value", searchCountryName);
setVariable.execute();
//the data in the suggest list is queried by a tree binding.
JUCtrlHierBinding hierBinding = (JUCtrlHierBinding) bindings.get("CountryView1");


//re-query the list based on the new bind variable values
hierBinding.executeQuery();

//The rangeSet, the list of queries entries, is of type
//JUCtrlValueBndingRef.
List<JUCtrlValueBindingRef> displayDataList = hierBinding.getRangeSet();

for (JUCtrlValueBindingRef displayData : displayDataList){
Row rw = displayData.getRow();
//populate the SelectItem list
selectItems.add(new SelectItem(
(Integer)rw.getAttribute("Id"),
(String)rw.getAttribute("Name")));
}

return selectItems;
}

onSuggest method for State field :


public List onStateSuggest(String searchStateName) {
ArrayList<SelectItem> selectItems = new ArrayList<SelectItem>();

System.out.println(searchStateName);
//get access to the binding context and binding container at runtime
BindingContext bctx = BindingContext.getCurrent();
BindingContainer bindings = bctx.getCurrentBindingsEntry();
//set the bind variable value that is used to filter the View Object
//query of the suggest list. The View Object instance has a View
//Criteria assigned
OperationBinding setVariable = (OperationBinding) bindings.get("setBind_StateName");
setVariable.getParamsMap().put("value", searchStateName);
setVariable.execute();
//the data in the suggest list is queried by a tree binding.
JUCtrlHierBinding hierBinding = (JUCtrlHierBinding) bindings.get("StateView1");


//re-query the list based on the new bind variable values
hierBinding.executeQuery();

//The rangeSet, the list of queries entries, is of type
//JUCtrlValueBndingRef.
List<JUCtrlValueBindingRef> displayDataList = hierBinding.getRangeSet();

for (JUCtrlValueBindingRef displayData : displayDataList){
Row rw = displayData.getRow();
//populate the SelectItem list
selectItems.add(new SelectItem(
(Integer)rw.getAttribute("Id"),
(String)rw.getAttribute("Name")));
}

return selectItems;
}

onSuggest method for City field :

public List onCitySuggest(String searchCityName) {
ArrayList<SelectItem> selectItems = new ArrayList<SelectItem>();

System.out.println(searchCityName);
//get access to the binding context and binding container at runtime
BindingContext bctx = BindingContext.getCurrent();
BindingContainer bindings = bctx.getCurrentBindingsEntry();
//set the bind variable value that is used to filter the View Object
//query of the suggest list. The View Object instance has a View
//Criteria assigned
OperationBinding setVariable = (OperationBinding) bindings.get("setBind_CityName");
setVariable.getParamsMap().put("value", searchCityName);
setVariable.execute();
//the data in the suggest list is queried by a tree binding.
JUCtrlHierBinding hierBinding = (JUCtrlHierBinding) bindings.get("CityView1");


//re-query the list based on the new bind variable values
hierBinding.executeQuery();

//The rangeSet, the list of queries entries, is of type
//JUCtrlValueBndingRef.
List<JUCtrlValueBindingRef> displayDataList = hierBinding.getRangeSet();

for (JUCtrlValueBindingRef displayData : displayDataList){
Row rw = displayData.getRow();
//populate the SelectItem list
selectItems.add(new SelectItem(
(Integer)rw.getAttribute("Id"),
(String)rw.getAttribute("Name")));
}

return selectItems;
}

Once after this, we could bind this to the af:autoSuggestBehavior's suggestedItems property

<af:inputText value="#{bindings.CountryId.inputValue}" label="#{bindings.CountryId.hints.label}"
columns="#{bindings.CountryId.hints.displayWidth}"
autoSubmit="true"
shortDesc="#{bindings.CountryId.hints.tooltip}" id="it3">
<af:autoSuggestBehavior suggestedItems="#{viewScope.AutoSuggestBean.onCountrySuggest}"/>
</af:inputText>
<af:inputText value="#{bindings.StateId.inputValue}" label="#{bindings.StateId.hints.label}"
columns="#{bindings.StateId.hints.displayWidth}"
autoSubmit="true" partialTriggers="it3"
shortDesc="#{bindings.StateId.hints.tooltip}" id="it4">
<af:autoSuggestBehavior suggestedItems="#{viewScope.AutoSuggestBean.onStateSuggest}"/>
</af:inputText>
<af:inputText value="#{bindings.CityId.inputValue}" label="#{bindings.CityId.hints.label}"
columns="#{bindings.CityId.hints.displayWidth}"
autoSubmit="true" partialTriggers="it4"
shortDesc="#{bindings.CityId.hints.tooltip}" id="it5">
<af:autoSuggestBehavior suggestedItems="#{viewScope.AutoSuggestBean.onCitySuggest}"/>
</af:inputText>

Finally, our output would be

output1.jpg

output2.jpg

output3.jpg

About

Tips and Tricks from Oracle's JDeveloper & ADF QA

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today