a4j:jsFunction in IE6/7 breaks when html:form’s prependId=”false”

Home / Blog / Java / a4j:jsFunction in IE6/7 breaks when html:form’s prependId=”false”

I wrote this article in JBoss Community. Here is another version of the same article. It is useful, when porting existing application from Ajax4JSF to use RichFaces.

In RichFaces3.2.2SR1, a4j:jsFunction generates an HTML script, which breaks in IE6/7, but works in FireFox. The issue is the way the jsFunction is rendered.

Here is a sample of how the script is rendered in Ajax4JSF and in RichFaces when html:form’s prependId attribute is false.

Notice that the name and id fields are kept same.

In Ajax4JSF, this will render as -


script id="func1" type="text/javascript"
function func1(){.........};
/script

In RichFaces, this renders as -


script id="func1" type="text/javascript">
func1 = function(){.........};
/script

Having the “id” of script tag and the func1 prototype “name” as same creates the problem. IE6/7 while parsing the script tag gives an error – “Object does not supports this property”.

In RichFaces the renderer for jsFunction is AjaxFunctionRendererBase. This renderer’s getFunction() method has changed from Ajax4JSF and generates this inappropriate javascript code.

A simple fix would be to set html:form’s prependId=”true”, which will append the form’s name to the “id” attribute, and the name and id will be different. There is a catch, in an existing application, then u will have to change all the javascript which uses the “id” to find the element.

The real fix would be to change the AjaxFunctionRenderer of RichFaces. Actually, its more like a workaround. If you are creating a new application from scratch, and using RichFaces, i will still use the RichFaces version.
Here is how to do it -
Create a new class extending the FunctionRenderer in RichFaces, and over-ride the getFunction method -


public class NewAjaxFunctionRenderer extends FunctionRenderer{
 /*
 * (non-Javadoc)
 *
 * @see org.ajax4jsf.framework.renderer.RendererBase#getComponentClass()
 */
 
 public static final String RENDERER_TYPE = "org.abc.AjaxFunctionRenderer";
 protected Class getComponentClass() {
 return HtmlAjaxFunction.class;
 }
 
 public String getFunction(FacesContext context, UIAjaxFunction component) {
 StringBuffer script = new StringBuffer();
 JSFunctionDefinition func = new JSFunctionDefinition();
 func.setName(component.getName());
 // Create AJAX Submit function.
 JSFunction ajaxFunction = AjaxRendererUtils.buildAjaxFunction(
 component, context,AjaxRendererUtils.AJAX_FUNCTION_NAME);
 Map options = AjaxRendererUtils.buildEventOptions(context, component);
 Map parameters = (Map) options.get("parameters");
 if (null == parameters) {
 parameters = new HashMap();
 options.put("parameters", parameters);
 }
 ajaxFunction.addParameter(JSReference.NULL);
 ajaxFunction.addParameter(options);
 // Fill parameters.
 for (Iterator it = component.getChildren().iterator(); it.hasNext();) {
 UIComponent child = (UIComponent) it.next();
 if (child instanceof UIParameter) {
 UIParameter parameter = ((UIParameter) child);
 String name = parameter.getName();
 func.addParameter(name);
 // Put parameter name to AJAX.Submit parameter, with default value.
 JSReference reference = new JSReference(name);
 if (null != parameter.getValue()) {
 reference = new JSReference(name + "||"
 + ScriptUtils.toScript(parameters.get(name)));
 
 }
 // Replace parameter value to reference.
 parameters.put(name, reference);
 }
 }
 func.addToBody(ajaxFunction.toScript());
 func.appendScript(script);
 return script.toString();
 }
}

In faces-config.xml add the new renderer for a4j:jsFunction –


 
 <renderer>
 <component-family>org.ajax4jsf.components.AjaxFunction</component-family>
 <renderer-type>
 org.ajax4jsf.components.AjaxFunctionRenderer
 </renderer-type>
 <renderer-class>
 org.test.NewAjaxFunctionRenderer
 </renderer-class>
 </renderer>
 

The tricky part is to find the component-family and renderer-type for AjaxFunctionRenderer. You can explode the richfaces jar and search the faces-config.xml to look for component-family and renderer-type for AjaxFunctionRenderer. Once you have it, this can be easily over-ridden in your application’s faces-config.xml as listed above.

Leave a Comment