X

The blog for hints & tips about Oracle Application Development Framework and Mobile Application Framework

  • ADFc
    November 7, 2010

How-to navigate in bounded task flows

Frank Nimphius
Master Principal Product Manager

A frequent question on OTN is of how to programmatically
navigate within bounded task flows. The use case usually is to perform navigation
in form of a non-action event, like e.g. a value change event.

Three options I am aware of that developers can use to perform
navigation in bounded task flows. It is important however to be conscious not
to fight the ADF controller framework.

A controller not only navigates between pages - or views as
it is referred to in ADFc - but it also keeps track of states, which is
especially important if bounded task flows are used. The three options to
navigate in bounded task flows are

·    Replacing
the current view port's viewId

·    Queue
an action on a command component

·    In
the case of a region, queue an event on the region component

 

The first of the
listed options
is to change the displayed viewId for a view port. A view
port in ADFc refers to the area displaying a view. This can be a region, or the
browser window. The following code below changes the viewId for the current
view port

ControllerContext
ccontext = ControllerContext.getInstance();

//set the viewId - the name of the view activity to

//go to - to display

String viewId = "EmployeesView";

ccontext.getCurrentViewPort().setViewId(viewId);

Be aware that this approach however bypasses the JSF
lifecycle. So you need to make sure - when using it - that not submitted data
gets submitted before changing the viewId as all changes are getting dismissed
when changing the viewId. So be conscious when using this code snippet in the
context of an event that is invoked by a component having its immediate
property set to true. Another restriction of this solution is that you can only
navigate to viewable targets. You cannot navigate to method or router
activities. If you need to have a non-viewable targets addressed then one of
the following options will work for you.

The second option
to programmatically perform navigation is to queue an action event on a
navigation component that is displayed or hidden (displayed = "false"
*not* rendered="false") on the view.

private
void navigateByQueueAction() {

   FacesContext fctx = FacesContext.getCurrentInstance();

   UIViewRoot root = fctx.getViewRoot();

   //client Id of button includes naming
container like id of region.

   RichCommandButton button =

           (RichCommandButton)
root.findComponent("r1:cb3");

   ActionEvent actionEvent = new
ActionEvent(button);

   actionEvent.queue();

}

The command button that the action event is queued for has
the navigation case defined in its action property. If you want t be flexible,
then you define wild card navigation rules to the activities you want to access
programmatically. The command button would be defined as hidden and act as a
proxy. If you follow a coding pattern in that wild card navigation rules are
constructed like <activityId>WCRule, then all target control cases become
predictable. E.g. to navigate to the "browseEmployees" view activity,
developers would know that the wild card navigation rule is
"browseEmployeesWCRule".

 

The third option
is if you don't like the idea of adding a proxy command component on views,
though you could try a command button in a page template to not have to add it
on all pages. In this case you queue the action event on the region containing
the bounded task flow. As you guessed, this option is not available for task
flows that are not displayed in a region.

Private
void navUsingQueueAction(ActionEvent actionEvent) {

 // the task flow is contained in a
region, so let's go and find it

  UIComponent  comp = actionEvent.getComponent();       

  while(!(comp instanceof RichRegion)){

      comp = comp.getParent();

  

  }

  RichRegion rr = ((RichRegion) comp);       

   rr.queueActionEventInRegion(
  

     createMethodExpressionFromString("browseEmployeesWCRule"),

     null, null, false, 0,
0,PhaseId.INVOKE_APPLICATION);               


 }

The code above queues the wild card event on the region,
which means there is no need for you to add hidden command components to the
views to act as a proxy. Instead you can - safely - assume that there exists an
instance of Rich Region on the page that you can find from the component that
needs to invoke navigation. The queueActionEventInRegion method has the
following signature, so you understand the API

public
void queueActionEventInRegion(

     javax.el.MethodExpression
actionExpression,

     javax.el.MethodExpression launchListenerMethodExpression,

     javax.el.MethodExpression returnListenerMethodExpression,

     java.lang.Boolean useWindow,

     java.lang.Integer windowWidth,

     java.lang.Integer windowHeight,

     javax.faces.event.PhaseId phaseId

)

The little helper method "createMethodExpressionFromString"
used in the sample, is listed below

private
MethodExpression createMethodExpressionFromString(String s){

    FacesContext fctx = FacesContext.getCurrentInstance();

    ELContext elctx =
fctx.getELContext();

    ExpressionFactory exprFactory =

          
fctx.getApplication().getExpressionFactory();

    MethodExpression methodExpr =
exprFactory.createMethodExpression(

                   elctx,              

                   s,

                   null,

                   new Class[]{}); 

    return methodExpr;

 }

Using option 2
and 3 actually has the ADFc controller performing the navigation, ensuring all
state is preserved and data is getting submitted to update the model. Option 1
is if you take care of necessary model updates or ensure the update model phase
is processed.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.