Skip Headers
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3)
B25386-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

11.8 Creating a Databound Shuttle

The selectManyShuttle and selectOrderShuttle components render two list boxes, and buttons that allow the user to select multiple items from the leading (or "available") list box and move or shuttle the items over to the trailing (or "selected") list box, and vice versa. Figure 11-22 shows an example of a rendered selectManyShuttle component. You can specify any text you want for the headers that display above the list boxes.

Figure 11-22 Shuttle (SelectManyShuttle) Component

Shuttle showing available list and selected list of items


Note:

In addition to using the supplied Move and Remove buttons to shuttle items from one list to the other, you can also double-click an item in either list. Double-clicking an item in one list moves the item to the other list. For example, if you double-click an item in the leading list, the item is automatically moved to the trailing list, and vice versa.

The only difference between selectManyShuttle and selectOrderShuttle is that in the selectOrderShuttle component, the user can reorder the items in the trailing list box by using the up and down arrow buttons on the side, as shown in Figure 11-23.

Figure 11-23 Shuttle Component (SelectOrderShuttle) with Reorder Buttons

Shuttle with reorder buttons on the side

11.8.1 How to Create a Databound Shuttle

In the SRDemo application, the SRSkills page uses a selectManyShuttle component to let managers assign product skills to a technician. Figure 11-24 shows the SRSkills page created for the sample application. The leading list box on the left displays products such as washing machines and dryers; the trailing list box on the right displays the products that a technician is skilled at servicing.

Figure 11-24 SelectManyShuttle Component on the SRSkills Page

Technician skills page for assigning skills with shuttle

To review and change product skill assignments, a manager first selects a technician's name from the dropdown list above the shuttle component. The application then displays the technician's existing skill assignments in the trailing list, as shown in Figure 11-25.

Figure 11-25 Shuttle Component with the Trailing List Populated

Technician skills page showing assigned skills in shuttle

Below the leading and trailing lists are optional boxes for displaying a description of a product. To view a description of a product, the manager can select an item from either list box, and the application displays the product's description in the box below the list.

To add new skill assignments, the manager selects the products from the leading list (Available Products) and then clicks the Move button.

To remove skills from the Assigned Skills list, the manager selects the products from the trailing list and then clicks the Remove button.

Like other ADF Faces selection list components, the selectManyShuttle component can use the f:selectItems tag to provide the list of items available for display and selection in the leading list.

Before you can bind the f:selectItems tag, create a class that maintains a list of the valid products (skills) for the shuttle, and the indexes of the products that are assigned to (selected for) a technician. The class should use the page's binding container to get the product master list for populating the shuttle's leading list. Example 11-59 shows the SkillsHelper class that is created to manage the population and selection state of the shuttle component on the SRSkills page.

Example 11-59 SkillsHelper Class

package oracle.srdemo.view;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
...
public class SkillsHelper {
    private BindingContainer bindings;
    private List<Product> productMasterList;
    private List <SelectItem> allProducts;
    private HashMap productLookUp;
    private int[] selectedProducts;
    private int skillsFor;
    private boolean skillsChanged = false;
    
    public List<SelectItem> getAllProducts() {
        if (allProducts == null) {
            OperationBinding oper = getBindings().getOperationBinding("findAllProduct");
            productMasterList = (List<Product>)oper.execute();
            int cap = productMasterList.size();
            allProducts = new ArrayList(cap);
            productLookUp = new HashMap(cap);
            //for(Product prod: products) {
            for (int i=0;i<cap;i++){
                Product prod = productMasterList.get(i);
                SelectItem item = new SelectItem(i, prod.getName(),prod.getDescription());
                allProducts.add(item);
                productLookUp.put(prod.getProdId(), i);
            }
        }
        
        return allProducts;
    }
 
    public void setAllProducts(List<SelectItem> allProducts) {
        this.allProducts = allProducts;
    }
 
    public void setSelectedProducts(int[] selectedProducts) {
        skillsChanged = true;
        this.selectedProducts = selectedProducts;
    }
 
    public int[] getSelectedProducts() {
        Integer currentTechnician = (Integer)ADFUtils.getBoundAttributeValue(getBindings(),"currentTechnician");
        
        if (currentTechnician != null){
            if (skillsFor != currentTechnician.intValue()){
                skillsFor = currentTechnician.intValue();
                skillsChanged = false;
                OperationBinding getAssignedSkillsOp = getBindings().getOperationBinding("findExpertiseByUserId");
                List<ExpertiseArea> skills = (List<ExpertiseArea>)getAssignedSkillsOp.execute();
                
                selectedProducts = new int[skills.size()];
                
                for (int i=0;i<skills.size();i++){
                    Integer lookup = (Integer)productLookUp.get(skills.get(i).getProdId());
                    selectedProducts[i] = lookup.intValue();
                }   
            }
        }
 
        return selectedProducts;
    }
 
    public List<Integer> getSelectedProductIds(){
        ArrayList prodIdList = new ArrayList(selectedProducts.length);
        for (int i:selectedProducts){
            prodIdList.add(productMasterList.get(i).getProdId());
        }
        return prodIdList;
    }
 
    public void setBindings(BindingContainer bindings) {
        this.bindings = bindings;
    }
 
    public BindingContainer getBindings() {
        return bindings;
    }
 
    public void setSkillsChanged(boolean skillsChanged) {
        this.skillsChanged = skillsChanged;
    }
 
    public boolean isSkillsChanged() {
        return skillsChanged;
    }
}

The methods of interest in the SkillsHelper class are getAllProducts() and getSelectedProducts().

The getAllProducts() method is the method that populates the shuttle's leading list. The first time this method is called, the findAllProduct() method on the SRPublicFacade session bean is invoked, and the list of products is cached in an array list of SelectItem objects. The getAllProducts() method also maintains a hashmap that enables reverse lookup of the list item index number based on the product ID.

The getSelectedProducts() method returns an array of int values, defining the list of items that appear on the shuttle's trailing list. This method also checks whether the currently selected technician (from the dropdown list above the shuttle) has changed. If the currently selected technician has changed, the findExpertiseByUserId() method on the SRAdminFacade session bean is invoked, and the new current technician's list of skills is retrieved and displayed in the trailing list of the shuttle.

The SkillsHelper class is maintained as a session scoped managed bean named skillsHelper. Example 11-60 shows the managed beans configured for working with the shuttle component in the SRDemo application.

Example 11-60 Managed Beans for the Shuttle Component in the faces-config.xml File

<managed-bean>
  <managed-bean-name>skillsHelper</managed-bean-name>
  <managed-bean-class>oracle.srdemo.view.SkillsHelper</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
  <managed-property>
    <property-name>bindings</property-name>
    <value>#{data.SRSkillsPageDef}</value>
  </managed-property>    
</managed-bean>
<managed-bean>
  <managed-bean-name>backing_SRSkills</managed-bean-name>
  <managed-bean-class>oracle.srdemo.view.backing.SRSkills</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

All the bindings of the SRSkills page are defined in the file app_management_SRSkillsPageDef.xml, a reference of which is injected into the SkillsHelper class. Example 11-61 shows the page definition file for the SRSkills page.

Example 11-61 Page Definition File for the SRSkills Page

<?xml version="1.0" encoding="UTF-8" ?>
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
                version="10.1.3.36.2" id="SRSkillsPageDef"
                Package="oracle.srdemo.view.pageDefs"..>
  <executables>
    <methodIterator id="findAllStaffIter" Binds="findAllStaff.result"
                    DataControl="SRPublicFacade" RangeSize="-1"
                    BeanClass="oracle.srdemo.model.entities.User"/>
    <methodIterator id="findAllProductIter" Binds="findAllProduct.result"
                    DataControl="SRPublicFacade" RangeSize="-1"
                    BeanClass="oracle.srdemo.model.entities.Product"/>
    <variableIterator id="variables">
      <variable Name="selectedStaffIdVar" Type="java.lang.Integer"/>
    </variableIterator>
  </executables>
  <bindings>
    <methodAction id="findAllStaff" InstanceName="SRPublicFacade.dataProvider"
                  DataControl="SRPublicFacade" MethodName="findAllStaff"
                  RequiresUpdateModel="true" Action="999"
                  ReturnName="SRPublicFacade.methodResults.SRPublicFacade_dataProvider_findAllStaff_result"/>
    <methodAction id="findAllProduct" InstanceName="SRPublicFacade.dataProvider"
                  DataControl="SRPublicFacade" MethodName="findAllProduct"
                  RequiresUpdateModel="true" Action="999"
                  ReturnName="SRPublicFacade.methodResults.SRPublicFacade_dataProvider_findAllProduct_result"/>
    <attributeValues IterBinding="variables" id="currentTechnician">
      <AttrNames>
        <Item Value="selectedStaffIdVar"/>
      </AttrNames>
    </attributeValues>
    <methodAction id="findExpertiseByUserId"
                  InstanceName="SRAdminFacade.dataProvider"
                  DataControl="SRAdminFacade" MethodName="findExpertiseByUserId"
                  RequiresUpdateModel="true" Action="999"
                  ReturnName="SRAdminFacade.methodResults.SRAdminFacade_dataProvider_findExpertiseByUserId_result">
      <NamedData NDName="userIdParam" 
                 NDType="java.lang.Integer"
                 NDValue="#{bindings.currentTechnician.inputValue}"/>
    </methodAction>
    <list id="findAllStaffList" StaticList="false" ListOperMode="0"
          IterBinding="variables" ListIter="findAllStaffIter" 
          NullValueFlag="1" NullValueId="findAllStaffList_null">
      <AttrNames>
        <Item Value="selectedStaffIdVar"/>
      </AttrNames>
      <ListAttrNames>
        <Item Value="userId"/>
      </ListAttrNames>
      <ListDisplayAttrNames>
        <Item Value="firstName"/>
        <Item Value="lastName"/>
      </ListDisplayAttrNames>
    </list>
    <methodAction id="updateStaffSkills"
                  InstanceName="SRAdminFacade.dataProvider"
                  DataControl="SRAdminFacade" MethodName="updateStaffSkills"
                  RequiresUpdateModel="true" Action="999">
      <NamedData NDName="userId"
                 NDValue="${bindings.currentTechnician.inputValue}"
                 NDType="java.lang.Integer"/>
      <NamedData NDName="prodIds" NDValue="${skillsHelper.selectedProductIds}"
                 NDType="java.util.List"/>
    </methodAction>
  </bindings>
</pageDefinition>

The next procedure assumes you've already created the relevant bindings, a class similar to the SkillsHelper class in Example 11-59, and configured the required managed beans in faces-config.xml, as shown in Example 11-60.

To create a shuttle component:

  1. From the ADF Faces Core page of the Component Palette, drag and drop SelectManyShuttle onto the page. JDeveloper displays the Insert SelectManyShuttle dialog, as illustrated in Figure 11-26.

    Figure 11-26 Insert SelectManyShuttle Dialog

    Insert SelectManyShuttle dialog for binding select items
  2. Select Bind to list (select items) and click Bind... to open the Expression Builder.

  3. In the Expression Builder, expand JSF Managed Beans > skills. Double-click allProducts to build the expression #{skillsHelper.allProducts}. Click OK.

    This binds the f:selectItems tag to the getAllProducts() method that populates the shuttle's leading list.

  4. In the Insert SelectManyShuttle dialog, click Common Properties. Click Bind... next to the Value field to open the Expression Builder again.

  5. In the Expression Builder, expand JSF Managed Beans > skills. Double-click selectedProducts to build the expression #{skillsHelper.selectedProducts}. Click OK.

    This binds the value attribute of the selectManyShuttle component to the getSelectedProducts() method that returns an array of int values, defining the list items on the shuttle's trailing list.

Example 11-62 shows the code for the selectManyShuttle component after you complete the Insert SelectManyShutle dialog.

Example 11-62 SelectManyShuttle Component in the SRSkills.jspx File

<af:selectManyShuttle value="#{skillsHelper.selectedProducts}"
                      ...
  <f:selectItems value="#{skillsHelper.allProducts}"/>
</af:selectManyShuttle>

For more information about using the shuttle component, see the ADF Faces Core tags at

http://www.oracle.com/technology/products/jdev/htdocs/partners/addins/exchange/jsf/doc/tagdoc/core/index.html

11.8.2 What Happens at Runtime

When the SRSkills page is first accessed, the variable iterator executes and instantiates its variable, selectedStaffIdVar. At this point, the variable does not contain a value. When the manager selects a name from the dropdown list, the variable is populated and the attribute binding can then provide the value for the findExpertiseByUserId() method's parameter userIdParam, using the EL expression for the value of the NamedData Element.

When the Save skill changes command button (see Figure 11-24) is clicked, the current technician's user ID and the associated array of product IDs (assigned skills) are retrieved and sent to the updateStaffSkills() method on the SRAdminFacade bean.

Example 11-63 shows the code for the commandButton component on the SRSkills.jspx page.

Example 11-63 CommandButton Component in the SRSkills.jspx File

<af:commandButton action="#{backing_SRSkills.saveSkillChanges_action}"
                  actionListener="#{bindings.updateStaffSkills.execute}"../>