How to Add New Choice to an af:selectOneChoice at Runtime

A question on the JDeveloper and ADF OTN forum asked for help on how to add a new choice to an af:selectOneChoise on the page during runtime. The selectOneChoice is based on is a table in the DB.
This sample shows how to do this using the HR DB schema. The workspace is built using JDev 11.1.1.7.0 but should work without a problem using 11.1.1.4.0 and higher too. You may be asked if you want to migrate, which you should answer with ‘Yes’. The sample can be downloaded using the link provided at the end of this blog.

As this is a real simple data model it only uses the REGIONS table from the HR DB schema. As we want to add new values to the regions table we need to generate entity and view object for the Regions table. We name the VO RegionsLov to make clear that we use this VO as base for a LOV in the UI. To add a new row into this table we implement a public method in the application module which we expose through the client interface of the am. This method isn’t needed as we could simply use createWithParams method from the VO, but the use case asked on the forum did use a method in the application module too.

    public void insertRegion(Integer id, String name) {
        if (id == null || name == null)
            throw new JboException("No Data!");
        Row row = getRegionsLov().createRow();
        row.setAttribute("RegionId", id);
        row.setAttribute("RegionName", name);
        getRegionsLov().insertRow(row);
        // commit is used here only because of the use case from the forum!
        this.getTransaction().commit();
    }

You see that the method uses a commit statement, which I prefer not to do. The reason for this is that you can’t reuse this method in other cases where no commit is allowed because there are other pending changed which you don’t want to commit at the moment. We can remove the commit and call the commit from a bean or directly from a button in the UI to make the method reusable.

We use the VO as dynamic list in the UI so we don’t need to add ViewAccessors or list attributes on the VO. Before we built the UI we add three temporary variables into the variables iterator of the pageDef file. Refer to Creating Variables and Attribute Bindings to Store Values Temporarily in the PageDef for information about how to do this. One variabel ‘RegionId’ (as Integer) is used to store the selection of the LOV we build, the other two ‘newRegionId’ (as Integer) and ‘newRegionName’ (as String) are used to create a new region row in the REGIONS table.
The LOV is built from a af:selectOneChoice which we generate by dragging the RegionsLov’s RegionId attribute onto the page and drop it as SelectOneChoice. The image below shows the binding as dynamik list

Define af:SelectOneChoise

Define af:SelectOneChoise


The whole UI looks like
Final UI

Final UI


Here we see the form with the two inputText components which store their values in temporary pageDef variables ‘newReginId’ and ‘newRegionName’. Here is the full pageDef file for reference:

<?xml version="1.0" encoding="UTF-8" ?>
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel" version="11.1.1.64.93" id="StartPageDef" Package="de.hahn.blog.addvaluesoc.view.pageDefs">
  <parameters/>
  <executables>
    <variableIterator id="variables">
      <variable Name="region" Type="java.lang.Integer"/>
      <variable Name="showregion" Type="java.lang.Boolean" DefaultValue="false"/>
      <variable Name="newRegionId" Type="java.lang.Integer"/>
      <variable Name="newRegionName" Type="java.lang.String"/>
    </variableIterator>
    <iterator Binds="RegionsLov" RangeSize="-1" DataControl="BAVSOCAppModuleDataControl" id="RegionsLovIterator"/>
  </executables>
  <bindings>
    <list IterBinding="variables" id="RegionId" DTSupportsMRU="true" StaticList="false" ListIter="RegionsLovIterator" NullValueId="PLEASE_SELECT"
          NullValueFlag="start">
      <AttrNames>
        <Item Value="region"/>
      </AttrNames>
      <ListAttrNames>
        <Item Value="RegionId"/>
      </ListAttrNames>
      <ListDisplayAttrNames>
        <Item Value="RegionName"/>
      </ListDisplayAttrNames>
    </list>
    <attributeValues IterBinding="variables" id="newRegionId1">
      <AttrNames>
        <Item Value="newRegionId"/>
      </AttrNames>
    </attributeValues>
    <attributeValues IterBinding="variables" id="newRegionName1">
      <AttrNames>
        <Item Value="newRegionName"/>
      </AttrNames>
    </attributeValues>
    <methodAction id="insertRegion" InstanceName="BAVSOCAppModuleDataControl.dataProvider" DataControl="BAVSOCAppModuleDataControl" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="insertRegion" IsViewObjectMethod="false">
      <NamedData NDName="id" NDValue="" NDType="java.lang.Integer"/>
      <NamedData NDName="name" NDType="java.lang.String"/>
    </methodAction>
  </bindings>
  <ResourceBundle>
    <PropertiesBundle xmlns="http://xmlns.oracle.com/adfm/resourcebundle" PropertiesFile="de.hahn.blog.addvaluesoc.view.BAVSOCViewControllerBundle"/>
  </ResourceBundle>
</pageDefinition>

Now we look at the running application:


Here we see that originally are only four regions present in the selectOneChoice, and we add a new one with the Id=5 and the name ‘aaaaaaaa’ which is inserted with a click on the ‘Insert New Region’ button. The button calls a method in a managed bean

    public void insertRegionListener(ActionEvent actionEvent) {
        // GET A METHOD FROM PAGEDEF AND EXECUTE IT
        // get the binding container
        BindingContainer bindings =
            BindingContext.getCurrent().getCurrentBindingsEntry();
        // get an ADF attributevalue from the ADF page definitions
        AttributeBinding attrId =
            (AttributeBinding)bindings.getControlBinding("newRegionId1");
        Integer id = (Integer)attrId.getInputValue();
        AttributeBinding attrName =
            (AttributeBinding)bindings.getControlBinding("newRegionName1");
        String name = (String)attrName.getInputValue();
        // get an Action or MethodAction
        OperationBinding method = bindings.getOperationBinding("insertRegion");
        if (method == null) {
            FacesMessage msg =
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Method insertRegion not found!",
                                 "");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            return;
        }

        // if there are parameters to set...
        Map paramsMap = method.getParamsMap();
        paramsMap.put("id", id);
        paramsMap.put("name", name);
        // execute the method
        method.execute();
        List errors = method.getErrors();
        if (!errors.isEmpty()) {
            Exception e = (Exception)errors.get(0);
            FacesMessage msg =
                new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(),
                                 "");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            return;
            // handle errors here errors is a list of exceptions!
        }

        // Get a attribute value of the current row of iterator
        DCBindingContainer dcBindings = (DCBindingContainer)bindings;
        DCIteratorBinding iterBind =
            (DCIteratorBinding)dcBindings.get("RegionsLovIterator");
        iterBind.executeQuery();

        // gat the form for refresh
        UIComponent ui = (UIComponent)actionEvent.getSource();
        ui = ui.getParent();
        ResetUtils.reset(ui);
        attrId.setInputValue(null);
        attrName.setInputValue(null);

        // PPR refresh a jsf component
        AdfFacesContext.getCurrentInstance().addPartialTarget(ui);

    }

The method first gets the entered parameters for the new region id and name, then calls the method to insert the data in the AM (insertRegion) and finally requires the iterator which is used for the selectOneChoice in the UI (RegionsLovIterator).

You can download the sample workspace which was built with JDev 11.1.1.7.0 and which uses the HR schema from the ADFEMG Sample Project BlogAddValueSOC.zip page.

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s