Creating Task Flow bindings on the fly

A very common demand from the community was support for adding regions at run time. The good news is that 11.1.2 release has support for adding regions dynamically which is now well supported by a task flow binding layer as well. Wow...excited? Please see
21.10 Configuring a Page To Render an Unknown Number of Regions in developers fusion developers guide to learn more about this topic. Let me give you a quick overview on the implementation. Its very easy.


1. Build the logic to return TaskFlowBindingAttributes list for dynamic task flows

First step is to build a managed bean to hold your business logic for building list of oracle.adf.controller.binding.TaskFlowBindingAttributes as shown in the following code snippet.

 private List<TaskFlowBindingAttributes> taskFlowBindings = new ArrayList<TaskFlowBindingAttributes>();  
   
 public void buidTaskflowBindings(){  
   
  TaskFlowBindingAttributes tfBindAttr1 = new TaskFlowBindingAttributes();  
  tfBindAttr1.setId("region1");  
  tfBindAttr1.setTaskFlowId(new TaskFlowId("/WEB-INF/dept-task-flow-definition.xml", "dept-task-flow-definition"));  
  taskFlowBindings.add(tfBindAttr1);  
    
  TaskFlowBindingAttributes tfBindAttr2 = new TaskFlowBindingAttributes();  
  tfBindAttr2.setId("region2");  
  tfBindAttr2.setTaskFlowId(new TaskFlowId("/WEB-INF/emp-task-flow-definition.xml", "emp-task-flow-definition"));  
  tfBindAttr2.setParametersMap("#{pageFlowScope.MyBean.parameterMap}");  
  taskFlowBindings.add(tfBindAttr2);  
 }  
   
 public List<TaskFlowBindingAttributes> getTaskFlowBindings() {  
  return taskFlowBindings;  
 }  
   

2. Generate the executable entry for multi task flow in the page definition file

Switch to the binding tab of your page, click on the '+' icon under the Executables section to generate the binding for multiTaskFlow. Please see the following image.


You may need to key in a unique identifier for the <multiTaskFlow> entry, and a value for taskFlowList as well. The taskFlowList will take an EL expression that returns the list of TaskFlowBindingAttributes at run time. In our case the method getTaskFlowBindings() returns the list(please refer this method in above code snippet).

Note: The multi task flow binding (multiTaskFlow) in the page definition identifies a list of bounded task flows used in the ADF region.

  <multiTaskFlow id="multiRegion1"   
  taskFlowList="#{pageFlowScope.MyBean.taskFlowBindings}"  
  xmlns="http://xmlns.oracle.com/adf/controller/binding" activation="deferred"/>  


3. Build the UI to host regions at run time

The last step is building the UI to host regions at run time. This example uses af:forEach for adding regions at run time as shown in the following page snippet.

 <af:forEach var="tf" items="#{bindings.multiRegion1.taskFlowBindingList}">  
  <af:region value="#{tf.regionModel}" id="reg${tf.name}"/>  
 </af:forEach>  

Update on July 17, 2014
While EL binding the IDs( for e.g id="reg${tf.name}" in the above code snippet) you must use immediate EL such as id="reg${tf.name}", NOT the deferred EL such as id="reg#{tf.name}".

Notes(from Fusion Developers Guide):

  • Limit the number of ADF regions that you create in a page to 10.
  • Each task flow binding inherits attributes defined for the multi task flow binding unless you override this behavior using the methods exposed by TaskFlowBindingAttributes.
  • Each task flow binding inherits parameters defined in the multi task flow binding in addition to those defined using the parametersMap property.

Download

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

A glance at the implementation

Run the main.jsf page and click on the 'Display More Taskflows' button.
You may notice that two task flows are getting added on the screen when you click on the button.


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html



Comments

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi Jobinesh,
    I followed this post and the regions displayed as you explained.

    Then I tried little different approach where I have a tabbed view on my page. On this tab, inside a showDetail I put the below code and it works.


    af:showDetailItem text="Detail" id="sdi1"
    af:region value="#{bindings.dynamicListBTFList.taskFlowBindingList[0].regionModel}"
    id="r1" rendered="true"
    af:showDetailItem


    Later, I tried to add a new tab dynamically to display a region displaying one of the binded taskflow using below code. You see that the value expression is same.

    In this case of dyanmically adding the region, the new tab displays nothing!


    RichRegion region = new RichRegion();
    region.setId("Region_" + (n++));

    FacesContext context = FacesContext.getCurrentInstance();
    ValueExpression vex =
    context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(),
    "#{bindings.dynamicListBTFList.taskFlowBindingList[0].regionModel}",
    Object.class);
    region.setValueExpression("value", vex);

    RichShowDetailItem newShowDetailItem = new RichShowDetailItem();
    newShowDetailItem .setDisclosed(Boolean.TRUE);
    newShowDetailItem .setRendered(Boolean.TRUE);

    newShowDetailItem .setId("DynamicTabID_" +
    (n++));
    newShowDetailItem.getChildren().add(region);
    mainTabbedPanel.getChildren().add(employeeShowDetailItem);
    AdfFacesContext.getCurrentInstance().addPartialTarget(mainTabbedPanel);

    Please suggest if this is possible to do.

    ReplyDelete
  3. Amit,
    sorry for the delayed response. Look like this support/fix(programmatically adding taskflow bindings) will be available on future release

    ReplyDelete
  4. Hi,
    I have a scenario where I have a parent page which is more like a dashboard where I have four regions which shows data for monitoring purpose of different reports of the application.

    * All there regions are put inside a panel Box with the command link to refresh the data in the regions.
    * The regions are dynamic regions where different task flow are assigned at runtime governed by their backing bean TaskFlow Id's (No input parameter for taskFlows).

    The problem I face is, I am able to restart the taskFlows in the regions to their default activity by hitting the refresh the link using this small piece off code.

    BindingContext bctx = BindingContext.getCurrent();
    BindingContainer bindings = bctx.getCurrentBindingsEntry();
    DCTaskFlowBinding taskflowBinding = (DCTaskFlowBinding) bindings.get("dynamicRegion2");
    taskflowBinding.getRegionModel().refresh(FacesContext.getCurrentInstance());

    But the iterators in the page fragments of the task flows are not getting me the fresh values in the DB, instead they give me the values that are fetched during the initial loading.

    So can anyone kindly tell me how to refresh the regions from the parent page such that it refresh's the taskflow and get a fresh values from DB very time it loads.

    Thanks and Regards,
    Vijai

    ReplyDelete
  5. Vijai,
    If you use VO, drag and drop the executeQuery action displayed in the data control panel to your taksflow and mark it as default method activity for your taskflow.Rest will be taken care by the framework

    ReplyDelete
  6. Hi Jobinesh,

    Cool idea, does makes sense. Thank you.

    Regards,
    Vijai

    ReplyDelete
  7. Programmatic adding taskflow bindings is still not available in Build JDEVADF_11.1.2.1.0_GENERIC_110907.2314.6081.

    ReplyDelete
  8. Hi Jobinesh,
    Thanks for Sharing this valuable test App.
    I ran your testApp.i was unable to retrieve,parameter map in jspx, with this syntax '#{tf.parameterMap['DepartmentId']}' , where tf is var in foreach. Can you please tell me how to access this parameter map in jsff/jspx ?
    Thanks in Advance,
    Siddi

    ReplyDelete
  9. Hi amit,

    About adding Region programmatically:

    you gotta specify region :
    RichRegion region = new RichRegion();
    region.setVisible(true);
    region.setRendered(true);

    It will be OK.

    ReplyDelete
  10. Hi, is there any option to create runtime showdetailsItem with different table?

    ReplyDelete
  11. Hi Jobinesh,

    Nice post.

    Do you have any ideas how to do it in release 1 ?

    Thanks.

    Ghazi

    ReplyDelete

Post a Comment