Pages

Sunday, March 6, 2011

Set the Initial Focus on a component in a Page or a Fragment

In ADF 11g you can use the initialFocusId property of the af:document component to set the input focus on a UIComponent. On the UIComponent you need to set id property and set the clientComponent property to true. And use this id in the initialFocusId property of the af:document component which is only located in a ADF Page. This is not so hard to do, but sometimes it can be tricky to find the id of a component when you use regions ( Bounded Task Flows ). To solve this you can use the developer tool of Google Chrome or the Firebug plugin of  Mozilla FireFox. Select the UIComponent and take a look at this id, you can remove the ::content part.


To set the focus on an UIComponent in a dynamic Region can be hard because this id of the component is not always the same. It depends which Task Flow you open first ( sometimes it is region1:1:input1 or region1:2:input1 ) . And the second problem you have that you need to use some javascript to set the focus.
The solution is to lookup the region UIComponent and try to find the UIComponent from there, get the clientId and use this value.

Here are some screenshot of the possible scenarios.
Set the focus on the Label 2 item, this is in the ADF page.
Same page but now I set the focus on the DepartmentName in the Department Dynamic Region.
New page but with a static Employee Region.

Example page with the af:document and initialFocusId property set on a managed bean
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<jsp:directive.page contentType="text/html;charset=UTF-8"/>
<f:view>
<af:document id="d1" title="Second" initialFocusId="#{Focus.focus}">
<af:form id="f1">
<af:panelStretchLayout id="psl1">
<f:facet name="center">
<af:region value="#{bindings.employee1.regionModel}" id="r1"/>
<!-- id="af_one_column_stretched" -->
</f:facet>
<f:facet name="top">
<af:toolbar id="t1">
<af:commandToolbarButton text="start Page" id="second"
action="start"/>
</af:toolbar>
</f:facet>
</af:panelStretchLayout>
</af:form>
</af:document>
</f:view>
</jsp:root>
view raw page.jspx hosted with ❤ by GitHub
The managed bean which controls the focus
package nl.whitehorses.adf.demo.beans;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import oracle.adf.controller.TaskFlowId;
import oracle.adf.share.ADFContext;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;
public class Focus {
// to make this work the UIComponent must have clientComponent="true"
public String getFocus() {
FacesContext facesContext = FacesContext.getCurrentInstance();
String clientId = null;
// only for the secondPage, this page contains no dynamic regions
if ("/secondView".equals(facesContext.getViewRoot().getViewId())){
clientId = "r1:0:it3";
}
// only for the startPage
if ("/startView".equals(facesContext.getViewRoot().getViewId())){
// what is the current Task Flow
TaskFlowId taskFlow =
(TaskFlowId)this.getExpression("DynamicRegion.dynamicTaskFlowId");
// in the region we need to find the component
UIComponent region = facesContext.getViewRoot().findComponent("r1");
UIComponent focus = null;
// department TF
if ( "/WEB-INF/department.xml#department".equals(taskFlow.getFullyQualifiedName()) ){
// find the Focus UIComponent in the department TF
// and get its clientId
focus = region.findComponent("it1");
// employee TF
} else if ( "/WEB-INF/employee.xml#employee".equals(taskFlow.getFullyQualifiedName())) {
// find the Focus UIComponent in the employee TF
// and get its clientId
focus = region.findComponent("it3");
}
if ( focus != null ) {
// found so use javascript to set the focus
clientId = focus.getClientId(facesContext);
ExtendedRenderKitService service =
Service.getRenderKitService(facesContext,
ExtendedRenderKitService.class);
service.addScript(facesContext,
" var b = AdfPage.PAGE.findComponent('"+clientId+"'); b.focus();"
);
} else {
// nothing found then set the startPage focus
clientId = null;
}
// nothing found then set the startPage focus, this
// can be handled without javascript
if ( clientId == null )
clientId = "it2";
System.out.println(new java.util.Date()+" focus on "+clientId);
}
return clientId;
}
private Object getExpression(String param) {
ADFContext adfCtx = ADFContext.getCurrent();
ELContext elContext2 = adfCtx.getELContext();
ExpressionFactory elFactory2 = adfCtx.getExpressionFactory();
ValueExpression valueExp2 =
elFactory2.createValueExpression(elContext2,
"#{"+param+"}",Object.class);
return valueExp2.getValue(elContext2);
}
}
view raw Focus.java hosted with ❤ by GitHub
Here is the example workspace

3 comments:

  1. Hi Biemond this post was very useful, it works for region with multiple pagefragments also.

    We have an issue, If an pagefragment is partially submited by a LOV, the focus goes to the first field in the page controlled by initialfocusid. How could we avoid the change of focus during partialsubmit.

    with Thanks,
    Raaj

    ReplyDelete
  2. Thanks Edwin for the nice article.But if a component present inside the af:iterator then i don't see the clientId.Is there any other way to get the clientId if the component present inside the af:iterator.

    Thanks,
    Naga

    ReplyDelete
  3. Thanks Edwin for the nice article.But if a component present inside the af:iterator then i don't see the clientId.Is there any other way to get the clientId if the component present inside the af:iterator.

    Thanks,
    Naga

    ReplyDelete