August 24th, 2008 by Lincoln Baxter III

Ajax4Jsf <a4j:form data=”broken!”>

A4J:Form is missing several specified ajax functions

(View this issue on the JBoss tracker here. Keep reading, there is a fix… download fix)

The issue:

When using the a4j:form component, the data=”#{managedBean.property}” the properties defined in the data element list are supposed to be available after the a4j event in the data JavaScript variable; however, with <a4j:form> the attribute is not correctly causing the JavaScript data variable to be populated. The data variable is always undefined, even if the managed bean property is set to a valid value. This is exhibited by the alert box as the value is displayed, “(undefined)”.

Example:

 

—-

The workaround:

Taking a look at the source code revealed that the <a4j:form> was not in fact including this behavior at all in the broadcast() method, which is where the data element processing occurs in the <a4j:commandButton>.

UIAjaxForm.broadcast()

    /* (non-Javadoc)
     * @see javax.faces.component.UIComponentBase#broadcast(javax.faces.event.FacesEvent)
     */
     public void broadcast(FacesEvent event)
               throws AbortProcessingException {
          // perform default
          super .broadcast(event);
          if (event instanceof  AjaxEvent) {
               // complete re-Render fields. AjaxEvent deliver before render response.
               setupReRender();
          }
     }

—-

In fact, however, if we modify the <a4j:form> broadcast() method to behave like its <a4j:commandButton> relative, we can still achieve this functionality!

Updated: UIAjaxForm.broadcast()

    public void broadcast(final FacesEvent event) throws AbortProcessingException
    {
        super.broadcast(event);
        if (event instanceof AjaxEvent)
        {
            this.setupReRender();
            Object data = this.getData();
            AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
            if (null != data)
            {
                ajaxContext.setResponseData(data);
            }
            String focus = this.getFocus();
            if (null != focus)
            {
                UIComponent focusComponent = RendererUtils.getInstance().findComponentFor(this, focus);
                if (null != focusComponent)
                {
                    focus = focusComponent.getClientId(context);
                }
                ajaxContext.getResponseDataMap().put(AjaxActionComponent.FOCUS_DATA_ID, focus);
            }
            ajaxContext.setOncomplete(this.getOncomplete());
        }
    }

—-

We’re set! I don’t particularly like to repeat this code, so I may get around to refactoring everything and submitting it back to the Ajax4JSF project. For now, though, this blog will have to do. I believe other functionality that was also broken included both the focus=”elementId” and the oncomplete=”javascriptCode”. As always, please feel free to improve and comment on this. Enjoy!
Lincoln Baxter, III

About the author:

Lincoln Baxter, III is the Chief Editor of Red Hat Developers, and has worked extensively on JBoss open-source projects; most notably as creator & project lead of JBoss Forge, author of Errai UI, and Project Lead of JBoss Windup. This content represents his personal opinions, not those of his employer.

He is a founder of OCPsoft, the author of PrettyFaces and Rewrite, the leading URL-rewriting extensions for Servlet, Java EE, and Java web frameworks; he is also the author of PrettyTime, social-style date and timestamp formatting for Java. When he is not swimming, running, or playing competitive Magic: The Gathering, Lincoln is focused on promoting open-source software and making technology more accessible for everyone.

Posted in JSF, OpenSource

Leave a Comment




Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.