How to programmatically set focus on an input component

The af:document component has a property InitialFocusId that allows you to define the Id of an input component that should take focus when a page initially loads. But how do you set the component focus for pages that are already rendered? A use case for this is a partial submit that executes logic on the server, after which the cursor focus in the UI needs to be set to a specific input component of a page or page fragment. The solution to this use case is JavaScript that is generated on the server and executed on the client.

The simplified sample I wrote contains of three input text fields and three command buttons. Initially, using the af:document InitialFocusId property, the cursor focus is set to the first input text field.

The command button send a partial submit to a managed bean on the server. The managed bean reads the component Id of the input text field to put the focus to from a client attribute that is defined on each command button. Using the MyFaces Trinidad ExtendedRenderKitService class, the managed bean sends a JavaScript call to the client to change the current component focus.

Important: By default, ADF Faces does not render all its user interface components as JavaScript objects. It only renders those components as JavaScript objects that have behavior, like a table that can have its columns moved. Input text components, for example, are rendered in HTML only, which means that the ADF client side JavaScript framework will not find a handle to the component unless you tell ADF Faces to create one. For this, you set the ClientComponent property of the input text fields to true. This also is required for the af:document InitialFocusId property to work.

Below is the managed bean code that handles the command button action and that composes and executes the JavaScript to set the client side UI focus.

import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import oracle.adf.view.rich.component.rich.input.RichInputText;
import oracle.adf.view.rich.component.rich.nav.RichCommandButton;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;
public
class FocusBean {
  public FocusBean() {
  }

 public String onSetFocus(ActionEvent event) {
   RichCommandButton rcb = (RichCommandButton)event.getSource();
   String focusOn = (String)rcb.getAttributes().get("focusField");
   FacesContext fctx = FacesContext.getCurrentInstance();
   UIViewRoot viewRoot = fctx.getViewRoot();
  //search can be improved to include naming containers
  RichInputText rit = RichInputText)viewRoot.findComponent(focusOn);
 if (rit != null) {
   String clientId = rit.getClientId(fctx); 
   //compose JavaScript to be executed on the client 
   StringBuilder script = new StringBuilder();
   //use client id to ensure component is found if located in
   //naming container  
   script.append("var textInput = ");
   script.append("AdfPage.PAGE.findComponentByAbsoluteId");
   script.append ("('"+clientId+"');");
 
   script.append("if(textInput != null){"); 
   script.append("textInput.focus();");
   script.append("}");
   //invoke JavaScript
   writeJavaScriptToClient(script.toString());
  }  
 }
  //generic, reusable helper method to call JavaScript on a client
  private void writeJavaScriptToClient(String script) {
    FacesContext fctx = FacesContext.getCurrentInstance();
    ExtendedRenderKitService erks = null;
    erks = Service.getRenderKitService(
                 fctx, ExtendedRenderKitService.class);
    erks.addScript(fctx, script);
  }
}

 As mentioned, the command buttons in the sample have a client attribute attached that I use to determine which input component should receive focus. The managed bean calls the client attribute here:

RichCommandButton rcb = (RichCommandButton)event.getSource();
String focusOn = (String)rcb.getAttributes().get("focusField");

 In the page definition, the client attribute is defined as

<af:commandButton text="Focus Field 2" id="commandButton1"
                   partialSubmit="true"
                   actionListener="#{FocusBean.onSetFocus}">
  <af:clientAttribute name="focusField" value="it2"/>
</af:commandButton>
<af:commandButton text="Focus Field 3" id="cb1"
                  partialSubmit="true"
 actionListener="#{FocusBean.onSetFocus}">
  <af:clientAttribute name="focusField" value="it3"/>
</af:commandButton>

In your custom implementation of this use case, you for sure will have your own way of determining the next focus target. The server side code however doesn't change much.

You can DOWNLOAD the sample workspace from here: http://blogs.oracle.com/jdevotnharvest/resource/SetFocusToField.zip


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