Create taskFlow and region binding at run-time, show n numbers of regions using multiTaskFlow- Oracle ADF

Sharing is Caring

This is very specific development requirement to create taskFlow and region binding at run-time to show n numbers of the region in the page
In this case initially, you don’t know how much regions required in the page as it depends on user activity.

you can see in http://irctc.co.in/ (Indian Railways) site
when user search for a train and check berth availability then a tab is generated at run-time with berth and fare details and it continues for each action, every time a new tab with new information is generated (n-number of tabs and taskFlow)

A very good article is published in Oracle Magazine (July – August 2014) by Frank Nimphius on this requirement, the article contains a very good description of each and every step and a sample application with whole functionality
I found it very interesting and good so giving a quick overview of TaskFlow on Fly

this functionality is implemented using multiTaskFlow element that uses taskFlow binding from the managed bean, task flow bindings in managed bean created using TaskFlowBindingAttributes
this class is used to set all properties of taskFlow binding at runtime

See Oracle docs (TaskFlowBindingAttributes)-
Set of attributes that define a TaskFlowBinding object. The taskFlowList attribute of the multiTaskFlow element of the page definition uses a list of object of this type to describe each taskflowBinding that the multiTaskflow binding contains. The order of this list defines the order of the region objects in the multiTaskflow binding. 

So in this post, I am using Departments and Employees table of HR Schema(Oracle) to create business components for Model part

Create viewCriteria in both view objects (Departments and Employees) to filter data using DepartmentId

 

Applied viewCriteria to viewObject at AM level (Edit Vo instance and shuttle viewCriteria to selected side)
After this created methods in AMImpl class to set value in both viewCriteria’s bind variables

    /**Method to filter Department ViewObject
     * @param deptId
     */
    public void filterDepartmentData(Integer deptId) {
        this.getDepartments1().setNamedWhereClauseParam("BindDeptId", deptId);
        this.getDepartments1().executeQuery();

    }

    /**Method to filter Employees Data
 * @param deptId
 */
    public void filterEmployeesData(Integer deptId) {
        this.getEmployees1().setNamedWhereClauseParam("BindDeptId", deptId);
        this.getEmployees1().executeQuery();

    }

Expose both methods to use in the client interface

Now viewController part-

Created two bounded task flow with one input parameter for DepartmentId (this id will be used to filter Departments and Employees view object)
One for Departments and Second for Employees-

First task flow has a .jsff (Facelets) page that has Departments viewObject as a form, just to show date with navigation buttons. filterDepartmentData method of AMImpl is used as Default Activity of this task flow to filter data before entering in page

The second task flow has a .jsff (Facelets) page that has Employees viewObject as a table. filterEmployeesData method of AMImpl is used as Default Activity of this task flow to filter data before entering in page

Now basic configuration is complete, the model is ready and bounded task flows are ready
then create a JSF page and managed bean (pageFlowScope) in adfc-config.xml, this page will make use of these two bounded task flows  and managed bean is responsible to generate taskFlow binding at runtime

Next Step is to prepare managed bean to hold taskFlowBinding-
Create a List of type TaskFlowBindingAttributes and it’s accessors

import oracle.adf.controller.binding.TaskFlowBindingAttributes;    
private List<TaskFlowBindingAttributes> taskFlowBinding = new ArrayList<TaskFlowBindingAttributes>(5);

    public void setTaskFlowBinding(List<TaskFlowBindingAttributes> taskFlowBinding) {
        this.taskFlowBinding = taskFlowBinding;
    }

    public List<TaskFlowBindingAttributes> getTaskFlowBinding() {
        return taskFlowBinding;
    }

Create multiTaskFlow binding in executables of the page-

    • Open JSF page, click on bindings tab of the page editor
    • click on green plus icon of executables section
    • Select ADF TaskFlow Bindings in the category and select multiTaskFlow

 

    • Click on ok and provide a unique value for id attribute and reference of List created in managed bean as value for taskFlowList attribute

 

 

    • The configuration of multiTaskFlow for this page is complete and now time to design page to render multiple regions. For this purpose add af:ForEach and a region inside it, forEach is responsible to add regions at run-time. here a little change I am using panelTabbed  to create tabs at runtime and inside the tab, there will be region
    • See this XML code- here nothing simple panelTabbed and forEach iterates over to list to identify the number of items and varStatus of forEach is used to create id of showDetailItem at runtime as id must be unique. regionModel is referenced from var attributes of forEach as part of taskFlowBinding

 <af:panelTabbed position="above" id="pt1" partialTriggers="b1">
            <af:forEach items="#{bindings.mtf1.taskFlowBindingList}" var="multiTF" varStatus="vs">
               <af:showDetailItem id="Tab#{vs.index+1}" text="#{multiTF.name}" partialTriggers="b1">
                  <af:region value="#{multiTF.regionModel}" id="r1#{vs.index}" partialTriggers="::b1"/>
               </af:showDetailItem>
            </af:forEach>
         </af:panelTabbed>

 

    • Now page is ready to show unknown (n) number of regions, here I am using two lists and a button on page First List is of all departments and the second one is static list to select information type (if user want to see Only Departments or Departments wise Employees) and button to execute and add taskFlow from managed bean as per selected Department and
    • Again a map is created in the managed bean to store input parameters for task flow and it will be used while setting and creating taskFlowBinding

    HashMap<String, Object> tfParam = new HashMap<String, Object>();
    public void setTfParam(HashMap<String, Object> tfParam) {
        this.tfParam = tfParam;
    }

    public HashMap<String, Object> getTfParam() {
        return tfParam;
    }

 

    • Finally, we will create taskFlow binding and set properties on button click (actionEvent of the button), See this code-

    /**Method to create and set properties in TaskFlowBinding

     * @param actionEvent

     */

    public void displayDepartmentAction(ActionEvent actionEvent) {

        //Clear List to show newly created regions only

        taskFlowBinding.clear();

        System.out.println("List Cleared -Size>" + taskFlowBinding.size());

        //Check that user selects value in both List (Uses component binding to check)

        if (deptIdBindVal.getValue() != null && showTypeBind.getValue() != null) {

            //Put value in TaskFLow Parameter map, deptIdBindVal is binding of list of departments on page

            tfParam.put("DeptIdParam", deptIdBindVal.getValue());

            //Only Shows Departments taskFlow, if user selectes "Only Departments"
            if ("Only Departments".equalsIgnoreCase(showTypeBind.getValue().toString())) {
                //Setting taskFlow properties
TaskFlowBindingAttributes tfAttr = new TaskFlowBindingAttributes();
                //Creating Unique Id
tfAttr.setId("Department_" + deptIdBindVal.getValue());
                //See bounded taskFlow name in WEB-INF and use here
tfAttr.setTaskFlowId(new TaskFlowId("/WEB-INF/DepartmentsBTF.xml", "DepartmentsBTF"));
                //This EL refers parameter map created in this managedBean
tfAttr.setParametersMap("#{pageFlowScope.MultiTaskFlowBean.tfParam}");
                //Finally add taskFlow to List
taskFlowBinding.add(tfAttr);
            } else { // Show both Departments and Employees
                //Creating Departments TaskFlow binding
TaskFlowBindingAttributes tfAttr = new TaskFlowBindingAttributes();
tfAttr.setId("Department_" + deptIdBindVal.getValue());
tfAttr.setTaskFlowId(new TaskFlowId("/WEB-INF/DepartmentsBTF.xml", "DepartmentsBTF"));
tfAttr.setParametersMap("#{pageFlowScope.MultiTaskFlowBean.tfParam}");
taskFlowBinding.add(tfAttr);
                //Creating Employee TaskFlow biniding
tfAttr = new TaskFlowBindingAttributes();
tfAttr.setId("Employees_" + deptIdBindVal.getValue());
tfAttr.setTaskFlowId(new TaskFlowId("/WEB-INF/EmployeesBTF.xml", "EmployeesBTF"));
tfAttr.setParametersMap("#{pageFlowScope.MultiTaskFlowBean.tfParam}");
taskFlowBinding.add(tfAttr);
            }
        }
    }

 

  • So Application with multiTaskFlow is ready, in this post, I have used these two bounded task flow to show in two tabs at run-time, in the same way, you can call multiple TFs or a single task flow multiple time. Now run application and see how it works

Initial page with two lists

Select Department and show type -click on the button

Select Department and show type -click on the button

Create taskFlow and region binding at run-time

 

  • Refer this post, Region Extreme: Multi-Task-Flow Binding to learn more about multiTaskFlow binding. In this Frank also told about how to use the dynamic view object instance to show different data at run-time, because if we use the same instance of viewObject in multiple task flow at the same time then it will not maintain state for each region to it is necessary to use dynamic instance and it’s binding in pageDef
  • Read more about regions and task flows- Using Task Flows as Regions

Sample ADF Application-Download

Cheers:) Happy Learning

Related Posts

An Oracle ACE, Blogger, Reviewer, Technical Lead working on Oracle ADF

0 thoughts on “Create taskFlow and region binding at run-time, show n numbers of regions using multiTaskFlow- Oracle ADF”

Leave a Reply

Your email address will not be published. Required fields are marked *