Tuesday, April 19, 2011

ADF 11g Programmatic partial page refresh (PPR) with dynamic regions


When working with bounded taskflows it is important to have the ability to interchange them on the page. Unfortunately when you do this you also have to call that section of the page to refresh the information.

In other words, you should call a Programmatic partial trigger in the backing bean of your application on a dynamic region on your main page.
Lets get started and create a new Project:

Delete the model project as you wont need it for this.
In your remaining view controller project create a JSF page with a stretch layout

Then create 3 Taskflows. These are going to be the menu and 2 pages that we are going to switch between when a menu items are clicked.
> menu-task-flow-definition.xml
> page1-task-flow-definition.xml
> page2-task-flow-definition.xml

Inside the each of the taskflows add a “view” component from the component pallet and then right clicked it selecting “Create Page Fragment”. Create a page fragment for each taskflow respective of it’s name.

Lets make a start on the menu page fragment and add a couple of buttons to be uses to change the page. We’ll be adding this taskflow to the left of our JSF page. When an item is clicked the Center panel is updated with the selected page. Open your two other pages and stick on a panel header with “Page1″, “Page2″ respectively or something that shows each page is different.

Next we’ll do some work on the JSF page. open your “adfc-config.xml” file (unbounded Taskflow). As the JSF isn’t a taskflow we’ll add this here. You might later need to have some kind of action for this page so it’s good practice to add this here.

Now we’ll add the “Start” facet to the JSF page. This is where we’ll put the menu item.

Drag the menu Taskflow from the Application Navigator into the start facet and select “Region” from the Create menu.

Next drag one of the page Taskflows onto the “Center” facet and select “Dynamic Region”. You will then be prompted to create a Managed bean. Create one.

Make a not of the ID of your dynamic region

This next bit is a little fiddly and I think there might well be a better way of doing this with adding the bean to the other pages. However this is the way I’ve gone about it. We’re now going to widen the scope of your backing bean to an application managed bean. Open the “adfc-cong.xml” and select “Managed Beans” change the scope of the bean we just created to Application.

Now that you’ve done this the binding created on the JSF page will be invalidated. Open the JSF and go to the “bindings”. Double click the dynamic taskflow. Removing the “backingbeanscope” part of the bind variable.

Now lets look at the Managed bean we created. In here we have the programmatic PPR. The 2 methods for changing the Taskflows will refresh the region. I’ve used a couple of methods for finding the region which are taken from other examples found on the web. You’ll need to put the name of the region on your JSF page into each of these methods.
package com.demo.vc.regions;
 
import java.util.Iterator;
 
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
 
import oracle.adf.controller.TaskFlowId;
import oracle.adf.view.rich.context.AdfFacesContext;
 
public class CenterRegion {
 
    private String taskFlowId1 = "/WEB-INF/page1-task-flow-definition.xml#page1-task-flow-definition";
    private String taskFlowId2 = "/WEB-INF/page2-task-flow-definition.xml#page2-task-flow-definition";
 
    //Default taskflow
    private String taskFlowId = taskFlowId1;
 
    public CenterRegion() {
    }
 
    public TaskFlowId getDynamicTaskFlowId() {
        return TaskFlowId.parse(taskFlowId);
    }
 
    //Called by the menu taskflow
    public String showPage1() {
        taskFlowId = taskFlowId1;
        AdfFacesContext.getCurrentInstance().addPartialTarget(
                                findComponentInRoot("r2"));
        return null;
    }
    //Called by the menu taskflow
    public String showPage2() {
        taskFlowId = taskFlowId2;
        AdfFacesContext.getCurrentInstance().addPartialTarget(
                                findComponentInRoot("r2"));
        return null;
    }
 
    /**
     * Locate an UIComponent in view root with its component id. Use a recursive way to achieve this.
     * @param id UIComponent id
     * @return UIComponent object
     */
    public static UIComponent findComponentInRoot(String id) {
        UIComponent component = null;
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext != null) {
            UIComponent root = facesContext.getViewRoot();
            component = findComponent(root, id);
        }
        return component;
    }
 
    /**
     * Locate an UIComponent from its root component.
     * Taken from http://www.jroller.com/page/mert?entry=how_to_find_a_uicomponent
     * @param base root Component (parent)
     * @param id UIComponent id
     * @return UIComponent object
     */
    public static UIComponent findComponent(UIComponent base, String id) {
        if (id.equals(base.getId()))
            return base;
 
        UIComponent children = null;
        UIComponent result = null;
        Iterator childrens = base.getFacetsAndChildren();
        while (childrens.hasNext() && (result == null)) {
            children = (UIComponent)childrens.next();
            if (id.equals(children.getId())) {
                result = children;
                break;
            }
            result = findComponent(children, id);
            if (result != null) {
                break;
            }
        }
        return result;
    }
}
With that done we now need to called the two methods from our menu Taskflow. Open the taskflow and put two “Method Call” items onto the taskflow. Then add two control flow cases going from the menu page fragment view to each of the respective methods. Also it’s wise to add a wildcard with a return flow case.

Change the “Fixed Outcome” of each of the method calls to the name of the flow case. And then add the method for changing the page from the Managed bean.

Finally we need to add the actions to each of our buttons on the Menu page fragment

Run the application and watch the magic of the page change when you click the button.
Download the project here: DynamicRegion

No comments:

Post a Comment