5

I have a though issue with JSF 2. I use Mojarra 2.1.14 with Primefaces 3.1.4

I have a page with 2 forms : formA and formB. The two forms contains each the ViewState in an hidden input field.

<h:form id="formA" binding="#{sessionBean.formA}">
    <h:commandButton value="formA" action="#{sessionBean.actionA}">
        <f:ajax/>
    </h:commandButton>
</h:form>

<h:form id="formB" binding="#{sessionBean.formB}">
    <h:commandButton value="formB" action="#{sessionBean.actionB}">
        <f:ajax/>
    </h:commandButton>
</h:form>

User submits formA with an Ajax action. Inside the Java action I update explicitly formA and formB (which are binded).

public void actionA(){
    FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().add(formA.getClientId());
    FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().add(formB.getClientId());
    System.out.println("action A!!");
}

public void actionB(){
    System.out.println("action B!!");
}

In the Ajax responses there is the HTML code for formA and formB ( element) and the ViewState.

JSF updates the HTML of formA and formB and set the ViewState of the calling form : formA. formB do not contains any ViewState.

User submit formB with an Ajax action. Because ViewState is not defined, postBack is false and the renderResponse is set to true in the RESTORE phase, skipping the INVOKE APPLICATION phase: the action is not called. After the response VIEW_STATE is updated and if user sumbit formB, the action is called.

Is it a JSF 2 bug or limitation? Or Do I do something wrong ?

You can find a maven projet on GitHub: https://github.com/nithril/jsf-multiple-form

Thanks in advance for your help!

Nicolas Labrot
  • 4,017
  • 25
  • 40

2 Answers2

4

Problem you are facing is connected with known issue with JSF JavaScript library. Workaround is to explicitly set client id of another form in rendered attribute of f:ajax tag:

<h:form id="formA" binding="#{sessionBean.formA}">
  <h:commandButton value="formA" action="#{sessionBean.actionA}">
    <f:ajax render=":formB @form"/>
  </h:commandButton>
</h:form>

<h:form id="formB" binding="#{sessionBean.formB}">
  <h:commandButton value="formB" action="#{sessionBean.actionB}">
    <f:ajax render=":formA @form"/>
  </h:commandButton>
</h:form>

More about this:

Community
  • 1
  • 1
partlov
  • 13,789
  • 6
  • 63
  • 82
  • Thanks for your answer. The 2 xhtml forms are loosely coupled. Sadly, to correct this issue I must strongly coupled the two. – Nicolas Labrot Feb 01 '13 at 23:17
  • On first link there is a JavaScript code which may fix this, maybe you should try with it first. You are using primefaces, so it should work. Knowing BalusC's approach that probably work. – partlov Feb 01 '13 at 23:30
  • I have test the BalusC script and it works. I use primefaces but it do not correct the case where component is refreshed using Java – Nicolas Labrot Feb 02 '13 at 09:12
2

There is an alternative trick if you use MyFaces 2.0.x / 2.1.x that will update the forms correctly, adding the following script:

window.myfaces = window.myfaces || {};
myfaces.config = myfaces.config || {};
//set the config part
myfaces.config.no_portlet_env = true; 

See JSF Ajax and Multiple Forms.

This option is a lot better because you don't need to worry about fix every place in your webapp where you use multiple forms, just add it to the main template and that's it.

lu4242
  • 2,318
  • 1
  • 15
  • 15