Rabu, 29 Januari 2014

Set focus and highlight in JSF


Notice

This article is targeted on JSF 1.2. Whilst this can be used in JSF 2.0 as well, a better JSF 2.0 implementation is provided by OmniFaces with its component. See also showcase example here.




The power of a PhaseListener

This article shows how to use a PhaseListener to set focus to the first input element which has a FacesMessage (which can be caused by a validation or conversion error or any other custom reason) and highlight all elements which has a FacesMessage. It is relatively simple, it costs effectively only a few lines inside the beforePhase of the RENDER_RESPONSE, two small Javascript functions for the focus and highlight and a single CSS class for the highlight.

Here is a sample form. Note the Javascript which should be placed at the very end of the HTML body, at least after the input element which should be focused and highlighted. The stuff is tested in a Java EE 5.0 environment with Tomcat 6.0 with Servlet 2.5, JSP 2.1 and JSF 1.2_07 (currently called Mojarra).

 id="form">
columns="3">
for="input1" value="Enter input 1" />
id="input1" value="#{myBean.input1}" required="true" />
for="input1" style="color: red;" />

for="input2" value="Enter input 2" />
id="input2" value="#{myBean.input2}" required="true" />
for="input2" style="color: red;" />

for="input3" value="Enter input 3" />
id="input3" value="#{myBean.input3}" required="true" />
for="input3" style="color: red;" />

/>
value="Submit" action="#{myBean.doSomething}" />
/>



This is how the Javascript functions setFocus() and setHighlight() should look like:

/**
* Set focus on the element of the given id.
* @param id The id of the element to set focus on.
*/

function setFocus(id) {
var element = document.getElementById(id);
if (element && element.focus) {
element.focus();
}
}

/**
* Set highlight on the elements of the given ids. It basically sets the classname of the elements
* to 'highlight'. This require at least a CSS style class '.highlight'.
* @param ids The ids of the elements to be highlighted, comma separated.
*/

function setHighlight(ids) {
var idsArray = ids.split(",");
for (var i = 0; i < idsArray.length; i++) {
var element = document.getElementById(idsArray[i]);
if (element) {
element.className = 'highlight';
}
}
}

And now the CSS style class for the highlight:

.highlight {
background-color: #fcc;
}

And finally the PhaseListener which sets the focus to the first input element which has a FacesMessage and highlights all input elements which has a FacesMessage:

/*
* net/balusc/webapp/SetFocusListener.java
*
* Copyright (C) 2007 BalusC
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library.
* If not, see .
*/


package net.balusc.webapp;

import java.util.Iterator;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

/**
* This phase listener checks if there is a client ID with message and will set the client ID as
* ${focus} in the request map. It will also gather all client IDs with message and will set it as
* ${highlight} in the request map.
*


* This phase listener should be configured in the faces-config.xml as follows:
*


* <lifecycle>
* <phase-listener>net.balusc.webapp.SetFocusListener</phase-listener>
* </lifecycle>
*

*
* @author BalusC
* @link http://balusc.blogspot.com/2007/12/set-focus-in-jsf.html
*/

public class SetFocusListener implements PhaseListener {

// Actions ------------------------------------------------------------------------------------

/**
* @see javax.faces.event.PhaseListener#getPhaseId()
*/

public PhaseId getPhaseId() {

// Listen on render response phase.
return PhaseId.RENDER_RESPONSE;
}

/**
* @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
*/

public void beforePhase(PhaseEvent event) {

// Init.
FacesContext facesContext = event.getFacesContext();
String focus = null;
StringBuilder highlight = new StringBuilder();

// Iterate over all client ID's with messages.
Iterator clientIdsWithMessages = facesContext.getClientIdsWithMessages();
while (clientIdsWithMessages.hasNext()) {
String clientIdWithMessages = clientIdsWithMessages.next();
if (focus == null) {
focus = clientIdWithMessages;
}
highlight.append(clientIdWithMessages);
if (clientIdsWithMessages.hasNext()) {
highlight.append(",");
}
}

// Set ${focus} and ${highlight} in JSP.
facesContext.getExternalContext().getRequestMap().put("focus", focus);
facesContext.getExternalContext().getRequestMap().put("highlight", highlight.toString());
}

/**
* @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
*/

public void afterPhase(PhaseEvent event) {
// Do nothing.
}

}

Define the SetFocusListener as follows in the faces-config.xml:

    
net.balusc.webapp.SetFocusListener


That's all, folks!

Back to top

Copyright - GNU Lesser General Public License

(C) December 2007, BalusC


Source:http://balusc.blogspot.com/2007/12/set-focus-in-jsf.html

Tidak ada komentar:

Posting Komentar