Search code examples
ajaxjsfrichfacesajax4jsf

Difference between a4j:commandButton and h:commandButton with a4j:ajax in it


I've got the following button:

<a4j:commandButton value="#{AppMessages['general.action.cancel']}"
            disabled="#{!entityBB.expandState.editable}"
            actionListener="#{entityBB.cancel}"
            render="initialServicePanel :messages" status="ajaxStatus"
            immediate="true" />

In my case the above button does everything I need (remove the inError state from an uiComponent to rerender it and reset (cancel) everything in the form to its previous state).

When I try to use it as this:

<h:commandButton value="#{AppMessages['general.action.cancel']}"
    disabled="#{!entityBB.expandState.editable}" immediate="true">
        <a4j:ajax execute="@this" render="initialServicePanel :messages"
        listener="#{entityBB.cancel}" status="ajaxStatus" />
</h:commandButton>

it isn't working (the value gets reset but the uiComponent (an inputText) stays red though in error). Why is this? I can't figure out the difference between the two of them since I thought an a4j:commandButton was just an h:commandButton with a4j:ajax in it behind the scenes.

EDIT: Now I've got another situation where the h:commandButton removes the value but keeps it in error (red border). And the a4j:commandButton removes it from in error (red border) but keeps the value.. It's the exact same input as above. I can't explain it.. Anyone?


Solution

  • The execute of <a4j:commandButton> defaults to @form, but the one of <a4j:ajax> defaults to @this, which means that only the "current component" is being executed (thus, the button itself). This caused that UIInput#decode() of input components aren't being called during apply request values phase. It's exactly that method which resets the validity back to true.

    To achieve exactly the same effect with <h:commandButton><a4j:ajax>, you need to explicitly set the execute attribute of <a4j:ajax> to @form as well.

    <h:commandButton ... value="Cancel" immediate="true">
        <a4j:ajax execute="@form" ... />
    </h:commandButton>
    

    Update: to clear out the field, which was your initial problem and which actually wouldn't have worked on <a4j:commandButton> either (so the "does everything I need" part is wrong), head to this answer for a breakdown of the problem and both a JSF 2.x and JSF 1.x targeted solution: Input fields hold previous values only if validation failed.