Thursday Sep 05, 2013

JDeveloper 11g R2 and 12c: How-to "virtually" press a button on page load

A frequent asked question is about how to press a command button upon load of a page or view. If you are on JDeveloper 11g R2 or JDeveloper 12c, then the solution to this programming challenge is the use of JavaServer Faces (JSF) 2 system events (If you are on JDeveloper 11g R1 then you are on JSF 1.2 and this JSF functionality doesn't exist).

System events are phase listeners that you  associate with a component instead of a view or page as a whole. In the use case mentioned above, the system event would be added to the command button you want to pres on initial page load, e.g.

<af:commandButton text="Press on Page Load" id="cb1"
       actionListener="#{viewScope.OnLoadHandler.onButtonPressed}"
       partialSubmit="true">
   <f:event listener="#{viewScope.OnLoadHandler.pressButton}" type="postAddToView"/>
</af:commandButton> 

 As you can see the f:event tag is added as a child tag to the af:commandButton (You find the event tag in the JDeveloper component palette under JSF -> Core) pointing to a listener defined in a managed bean that listens for the "postAddToView" phase. The managed bean is configured in viewScope to ensure the button in the use case is only "virtually pressed" once and not upon PPR of the button area. Using a managed bean in view scope, a flag can be kept that determines whether or not the button has been invoked already.

The event handler uses JavaScript to "virtually press" the button after the page or view is loaded:

...

boolean initialPageLoad = false;

...

public void pressButton(ComponentSystemEvent componentSystemEvent) {
 //only execute button once and not on PPR is used
 if (initialPageLoad == false) {
  //get access to the command button to execute "click"
  RichCommandButton rc = (RichCommandButton)componentSystemEvent.getComponent();
  String clientId = rc.getClientId();

  //compose the JavaSCript to invvoke from the server. The button client ID allows 
  //us to locate the button even if it is saved in a naming container (e.g. a region) 
  //so the absolute component access will do
  String javaScript = "var button = AdfPage.PAGE.findComponentByAbsoluteId('"+clientId+"');
                      AdfActionEvent.queue(button,true)";
    
  //invoke the JS
  FacesContext facesContext = FacesContext.getCurrentInstance();
  ExtendedRenderKitService service = Service.getRenderKitService(facesContext, 
                                              ExtendedRenderKitService.class);
  service.addScript(facesContext, javaScript);

  //change flag   
  initialPageLoad = true;
 }
}

 This way, whatever is configured for the command button press is executed upon page / view load.

A valid question is: "why don't you execute the Java method associated with a command button directly instead of  using JavaScript?" The answer to this is that using JavaScript, associated behavior tags (e.g. for printable behavior or to show a popup) are executed too as it "mimic" a user behavior.

Of course, if there is no client side behavior associated with a command button, its better to not use JavaScript but call the Java method associated with the button directly.

 Frank




Monday Jul 23, 2012

How-to reset ADF Faces inputFile components

When working with the ADF Faces input file component, you'll notice a change in the UI after uploading a file in that the file name is displayed as a label and the upload button text changes to Update.

From a use case perspective this behavior may be fine if you bind the component value property to a managed bean that you want to update with changed file uploads. For generic file upload functionality though you probably prefer the input file to reset its state to the original display: input field and upload button text as "Browse".

To achieve this, you need to explicitly reset the input file component in a call to resetValue() on the RichInputFile component instance.

You can access the RichInputFile component instance from a JSF component binding to a manage bean (sub-optimal) or from a dynamic component lookup (recommended) in the component tree, using the UIViewRoot as a starting point or using Apache MyFaces Trinidad ComponentUtils:

http://myfaces.apache.org/trinidad/trinidad-api/apidocs/org/apache/myfaces/trinidad/util/ ComponentUtils.html

Thursday Feb 23, 2012

How-to define a default action for page fragments

The af:form component has a DefaultCommand property that, when set to the component Id of a command component like af:commandButton invokes the associated command action when the enter key is pressed anywhere in this form. However, if the form fields are contained in a page fragment exposed in a region then using the DefaultCommand property may not be an option as it is difficult to predict the command button id and its surrounding naming containers.

A solution to this is to use JavaScript on the UI input components that, when the Enter key is pressed virtually press a button within the page fragment (note that the af:form element belongs to the parent page and that you can only have a single af:form component per browser page)

Let's assume a page fragment with a single input text component and a command button to press:

<af:panelFormLayout id="pfl1">
  <f:facet name="footer">
     <af:commandButton text="Print Field Value" id="cb1" partialSubmit="true"                                            
                       clientComponent="true" action="#{View1Bean.onButtonPressed}"/>
   </f:facet>
   <af:inputText label="Enter Field" id="it1" binding="#{View1Bean.inputTextField}">
      <af:clientListener method="onFieldEnterKey" type="keyUp"/>
   </af:inputText>  
</af:panelFormLayout>

The command button is bound to a managed bean action method. By default, the action method is invoked when users press the command button. However, with the JavaScript shown next, this can be simulated and mapped to the Enter key press in the text field.

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:af=http://xmlns.oracle.com/adf/faces/rich
          xmlns:f="http://java.sun.com/jsf/core">

<af:resource type="javaScript">
   //function called by the client listener

  function onFieldEnterKey(inputEvent){
    if (event.getKeyCode() == AdfKeyStroke.ENTER_KEY) {
      //get the input text component from the event            
      var inputTextField = inputEvent.getSource();
      //the button is relative to the input text field so
      //relative search will do with no worrying about naming
      //containers
      var defaultButton = inputTextField.findComponent('cb1');
      //perform a partial submot
      var partialSubmit = true;
      AdfActionEvent.queue(defaultButton,partialSubmit);
      //Enter key does not need to go to server as we
      //queued a new event
       event.cancel();
   }
}
</af:resource>

For JavaScript to work, note the use of the af:clientListener on the input text field and the use of the clientComponent="true" configuration on the button.

Tuesday Nov 22, 2011

Creating ADF Faces Comamnd Button at Runtime

In ADF Faces, the command button is an instance of RichCommandButton and can be created at runtime. While creating the button is not difficult at all, adding behavior to it requires knowing about how to dynamically create and add an action listener reference. The example code below shows two methods: The first method, handleButtonPress is a public method exposed on a managed bean.

public void handleButtonPress(ActionEvent event){ 
 System.out.println("Event handled"); 
 //optional: partially refresh changed components if command 
 //issued as a partial submit
}

The second method is called in response to a user interaction or on page load and dynamically creates and adds a command button. When the button is pressed, the managed bean method – the action handler – defined above is called. The action handler is referenced using EL in the created MethodExpression instance. If the managed bean is in viewScope, backingBeanScope or pageFlowsScope, then you need to add these scopes as a prefix to the EL (as you would when configuring the managed bean reference at design time)

//Create command button and add it as a child to the parent component that is passed as an 
//argument to this method
private void reateCommandButton(UIComponent parent){
  RichCommandButton edit = new RichCommandButton();
  //make the request partial
  edit.setPartialSubmit(true);
  edit.setText("Edit");                         
  
  //compose the method expression to invoke the event handler
  FacesContext fctx = FacesContext.getCurrentInstance();
  Application application = fctx.getApplication();
  ExpressionFactory elFactory = application.getExpressionFactory();
  ELContext elContext = facesCtx.getELContext();
  MethodExpression methodExpressio = null;
  //Make sure the EL expression references a valid managed bean method. Ensure
  //the bean scope is properly addressed 

  methodExpression =  elFactory.createMethodExpression( 
                            elContext,"#{myRequestScopeBean.handleButtonPress}", 
                            Object.class,new Class[] {ActionEvent.class});
  //Create the command buttonaction listener reference

  MethodExpressionActionListener al = null;        
  al= new MethodExpressionActionListener(methodExpression); 
  edit.addActionListener(al); 

   //add new command button to parent component and PPR the component for 
   //the button to show
   parent.getChildren().add(edit);
   AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance(); 
   adfFacesContext.addPartialTarget(parent); 
}
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