Monday, June 30, 2014

af:SelectManyChoice component to display the child ViewObject rows as list of items

Here is a requirement to render the child viewobject rows as list of values in a multi selection component like af:selectManyChoice. This is not similar to the selectManyChoice what we usually build for af:query component. Here we are going to enable the multiselection for an LOV in an input form and that multi select component renders the associated child rows as selected values and also, selecting an item from the LOV will create a new row in the child table. The objectives of the experiment are,
  1. Enabling multiselection for LOV attribute of a view object.
  2. Render the child viewobject rows as selected items in a selectManyChoice component
  3. Selecting an item from selectManyChoice LOV, will create a new row in the child table. 
Here I am taking HR schema for building this sample application. The use case is that user may want to mark the employee as a manager to one or more departments which are selected from a departments multi select LOV, in an employee create/update ADF input form. The component 'Mgr To Department' in UI is a selectManyChoice listing all the departments from the Department table (in fact the LOV list can be from any base table or a static LOV, in real world scenarios). The below is an example screen shot and it says that the employee Id 1102 is a manager to two departments with id's 130 and 140.

User can select any number of departments from LOV and save it. You can follow the below steps for building this,

Enabling multi selection for an LOV attribute: 

Declaratively we can not build a multi selection for an LOV attribute, here we need a tweak a bit in source of a VO. The idea is first to create an ViewObject (for LOV) and expose it as a viewaccessor in the parent viewobject (with which you are going to build input form). Now create a EO based transient attribute(create it in EO and then add it to VO), and build LOV for it using the viewaccessor just exposed. As I mentioned, we need to convert this LOV to multi selection enabled, so please go the source of the viewobject do as below
  • change the value attribute of CONTROLTYPE to 'delimited_ids_choice'. 
  • Add Delimiter="," to the list binding of that LOV.
Transient attribute 'MgrToDepartment' at EO level:
 <Attribute
    Name="MgrToDepartment"
    Precision="255"
    ColumnName="MGR_TO_DEPARTMENT"
    SQLType="VARCHAR"
    Type="java.lang.String"
    ColumnType="VARCHAR2"
    IsQueriable="false"
    IsPersistent="false"/>

Transient attribute 'MgrToDepartment' at VO level: 
<ViewAttribute
    Name="MgrToDepartment"
    IsQueriable="false"
    PrecisionRule="true"
    EntityAttrName="MgrToDepartment"
    EntityUsage="Employees"
    LOVName="LOV_MgrToDepartment"    
    AliasName="MGR_TO_DEPARTMENT"
    Expression="MGR_TO_DEPARTMENT">
    <Properties>
      <SchemaBasedProperties>
        <DISPLAYWIDTH
          Value="40"/>
        <CONTROLTYPE
          Value="delimited_ids_choice"/>
      </SchemaBasedProperties>
    </Properties>
  </ViewAttribute>
List Binding of the LOV: 
<ListBinding
    Name="LOV_MgrToDepartment"
    ListVOName="DepartmentsLOV"
    ListRangeSize="-1"
    Delimiter=","
    NullValueFlag="none"
    NullValueId="LOV_MgrToDepartment_LOVUIHints_NullValueId"
    MRUCount="0">

Also make sure that 'IsSelected=false' is not present for the transient attribute at the VO level.
Now the LOV is ready in the model layer and need to drop it as a multi select component in the UI. You can drag and drop the view object instance as an input form in UI page and now you need to change the default LOV component generated by IDE to a selectManyChoice component. The code looks as below,  
Now you may have noticed that I used backingbean logic for 'value' expression. Actually I tried with different expressions on pagedef list binding 'MgrToDepartment' but I couldn't get the desired of result of passing comma separated values (eg: 130,140) of the selected departments to the model layer. And the below logic in managed bean worked form me,   


With this, you should be able to pass the selected departments as comma separated values to model layer, and I will discuss about accessing these values in the model layer for saving the selected department records to the Departments table with the manager id as the current employee id from the Employee table, later in this post.

Render the child viewobject rows as selected items in a selectManyChoice component:

As you know selectManyChoice here, sends/reads the selected values as comma separated values to/from model layer, so for rendering the list of departments as selected values (i.e the deparment id's for which the current employee is a manager) in the LOV we need to change the Employee view object query so that it reads the list of departments as comma separated values. The below is the snap shot of employee VO query after change,

Here I am reading the list of departments for which an employee is a manager, to the transient attribute 'Mgr_To_Department' and whenever the query is execute on VO, then the transient attribute will have the departments as comma separated values. Now the UI has this transient attribute as select many LOV and we should see these departments as, selected values in the selectManyChoice LOV when the UI renders.

Selecting an item in selectManyChoice list items, will create a new row in the child viewobject:

Now lets go back to the case when an user select a department id from the LOV and clicks on commit, then the selected department (in the Department table) should get their manager id set to the current employee id. So to make that happen we need to write the logic accordingly, making use of entity associations between Department and Employee table.

As we know we are going to get the comma separated values for the transient attribute 'Mgr_To_Department', need to manipulate that list in the doDML() method of the entity, so first enable the Entity Impl class for Employees entity and override the doDML() method as below. 

In the doDML(), for the respective state of the entity, we can write our own logic of creating child records using the entity accessors. In this example I didn't complete the whole flow of setting the manager id of the selected departments as the current row employee id.

You can download the example application from the following link. SelectManyChoice.zip

References:
Thanks to Jobinesh blog where I picked the initial stuff of enabling the multi selection for an LOV.
Declaratively-enabling-multiple-value.html






No comments:

Post a Comment