2010年11月24日星期三

SelectOneChoice as a table’s filter input component

Technorati Tags: ,,,

When displaying data into tables and using the out-of-the-box filtering feature, an input box is used to input the filter data. But in some scenarios, you may want to use a SelectOneChoice for an attribute that has a list of value.  Sometimes, a LOV may be used if the list of value is of very large size, we will explore a LOV filter in the next section.

We will use the HR schema’s COUNTRIES and REGIONS tables for this demonstration.

The source code of this demonstration can be downloaded here: TableFilterDemo

Step 1. Create an Application with a Model project and a ViewController project.

Step 2. Create ADF BC components from tables: COUNTRIES, REGIONS. EO, VO and association, view link and AM are automatically created.  I would like to change all the attribute with a type of BigDecimal to the type of Number.

Now, the Model project is like below:

filter-model-project

Step 3. Let’s modify the CountryView to include the region name.

  3.1. Add the RegionEO into the CountryView object;

  3.2. Add RegionId and RegionName attributes of RegionEO into the CountryView’s attributes.

Step 4. Create a read only LOV for RegionID in the Regions table, named it RegionsList. The SQL is : SELECT region_id, region_name FROM regions

Step 5. Assign the RegionsList LOV to the CountryView as a View Accessor.

Step 6. Add a List of Value for the RegionId attribute in the CountryView VO.

Add LOV

Add_LOV2

In the UI hints tab:

Select the ‘Choice List’ and uncheck the ‘No Selection’ Item.

Save all the changes.

Step 7.  Now we can test the BC in the BC browser, from the BC browser, we can see that the region Id now is displayed as a Choice List.

LOV-test

Now we are going to create the web page.

The data control now is as below:

filter-datacontrol

Step 8. Create a page, name it Countries.jspx. Drag and drop the CountryView1 into the page, Create it as a read only table and select the ‘Filtering’  and ‘Row Selection’ checkbox. For the regionId column, set the rendered as ‘false’ (not necessary).

Please pay attention to the fact that the VarStatus attribute of the table is set to ‘vs’ automatically, which we will use.

Step 9. For the Region Name column, in the Column facets, select the filter facet and insert a SelectOneChoice into the filter facet, set the label of the SelectOneChoice to ‘’.

Note: since the SelectOneChoice component will return the index of the selected value, not the direct value, we have to configure the SelectOneChoice as below.

<af:selectOneChoice id="soc1"
                                 value="#{vs.filterCriteria.RegionId}">
               <af:forEach var="listrow">
                 <f:selectItem id="si1"/>
               </af:forEach>
             </af:selectOneChoice>

it’s important to change the value expression of the SelectOneChoice to :#{vs.filterCriteria.RegionId}. You would better use the expression builder to construct the expression. The vs object is under the ‘JSP Object’ folder.

select-value-setting

Then we have to assign list to the SelectOneChoice component and assign the itemValue and itemLabel to the the selectedItem.

Step 10. Adding  a bindings for the tree(or list).

  10.1. go the bindings of the page: add. The item to be created is a tree.

  tree-binding

   10.2 create the tree binding:

create tree binding

    10.3. Save and then go back to the source to configure the SelectOneChoice.

      the items attribute is configured to : items="#{bindings.RegionsList1.rangeSet}" , using the expression builder will help you correctly assign the expression.

      the SelecteItem’s itemValue=”#{listrow.RegionId}”itemLabel=”#{listrow.RegionName}”

     the final SelectOneChoice’s code is:

<af:selectOneChoice id="soc1"
                                  value="#{vs.filterCriteria.RegionId}"
                                  valuePassThru="true">
                <af:forEach var="listrow"
                            items="#{bindings.RegionsList1.rangeSet}">
                  <f:selectItem id="si1" itemLabel="#{listrow.RegionName}"
                                itemValue="#{listrow.RegionId}"/>
                </af:forEach>

</af:selectOneChoice>

Step 13. Let’s run the page.

Step 14. The SelectOneChoice works in some degree, but the ‘Enter’ has to be pressed to submit the filter request, even autoSubmit of the SelectOneChoice doesn’t work.

Step 15. Let’s add a client listener to solve this problem. Add a client listener to the SelectOneChoice with the following code:

<af:clientListener method="executeSelection"
                                  type="valueChange"/>

Step 16. add the executeSelection javascript code in the page.

<f:facet name="metaContainer">
      <af:resource type="javascript">
          function executeSelection(event){
            jsEl= document.getElementById(event.getSource().getClientId());
            if(document.createEvent){
              // FF
              var evt = document.createEvent("KeyboardEvent");
              evt.initKeyEvent(                                                                                     
                               "keydown",        //  in DOMString typeArg,                                                          
                                true,             //  in boolean canBubbleArg,                                                       
                                true,             //  in boolean cancelableArg,                                                      
                                null,             //  in nsIDOMAbstractView viewArg,  Specifies UIEvent.view. This value may be null.    
                                false,            //  in boolean ctrlKeyArg,                                                              
                                false,            //  in boolean altKeyArg,                                                       
                                false,            //  in boolean shiftKeyArg,                                                     
                                false,            //  in boolean metaKeyArg,                                                      
                                 13,               //  in unsigned long keyCodeArg,                                                     
                                 0);
              jsEl.dispatchEvent(evt);
            }else{
              // IE
              evt = document.createEventObject();
              evt.keyCode = 13;
              jsEl.fireEvent("onkeydown", evt);
            }
          }
      </af:resource>
      </f:facet>

Step 17. run the page again.

There is one problem when select the region from the list, although the table can be filtered, the list’s current value cannot be recovered. It’s of course a SelectOneChoince’s problem, have to fix it.