How-to navigate in bounded task flows

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.

Comments:

Post a Comment:
Comments are closed for this entry.
About

The Oracle JDeveloper forum ranks in the Top 5 of the most active forums on the Oracle Technology Network (OTN).



The OTN Harvest blog is a summary of selected topics posted on the OTN Oracle JDeveloper forum.



It is an effort to turn knowledge exchange into an interesting read for developers who enjoy little nuggets of wisdom





Frank Nimphius

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today