问题
I got a strange behaviour on dynamicly included page
My first page has a combo to choose from different pages to include :
<h:panelGrid columns="2">
<h:outputLabel value="Choose your page to include" />
<h:selectOneMenu id="pageList" value="#{anyPageBean.page}">
<f:selectItems value="#{anyPageBean.pageList}" var="w" itemValue="#{w}" itemLabel="#{w}" />
</h:selectOneMenu>
</h:panelGrid>
The AnyPageBean just gives back one of the 2 following pages : pilotNoTemplate.xhtml or pipo.xhtml
@ManagedBean
@SessionScoped
public class AnyPageBean {
private String page;
private java.util.List<String> pageList;
public AnyPageBean() {
super();
pageList = new ArrayList<String>();
pageList.add("pilotNoTemplate.xhtml");
pageList.add("pipo.xhtml");
}
The pilotNoTemplate.xhtml appears correctly when i choose that page (the pipo page also).
But when i submit the form from pilotNoTemplate.xhtml, JSF considers that submit as a POST which is OK, but only Phase1 and Phase 6 are spanned, WHY ? I have a PhaseListener showing the Phases, it prints :
INFO IN pour /jsf2-todo-001-dynamic-page-include-v2/any.faces ¤¤¤¤¤ POST
INFO AJAX BEFORE RESTORE_VIEW 1 for viewId=null
INFO AJAX AFTER RESTORE_VIEW 1 for viewId=/any.xhtml
INFO AJAX BEFORE RENDER_RESPONSE 6 for viewId=/any.xhtml
INFO AJAX AFTER RENDER_RESPONSE 6 for viewId=/any.xhtml
If anything was filled in the form, it gets resetted ...
the SECOND submit is all right, all the phase are spanned :
INFO IN pour /jsf2-todo-001-dynamic-page-include-v2/any.faces ¤¤¤¤¤ POST
INFO AJAX BEFORE RESTORE_VIEW 1 for viewId=null
INFO AJAX AFTER RESTORE_VIEW 1 for viewId=/any.xhtml
INFO AJAX BEFORE APPLY_REQUEST_VALUES 2 for viewId=/any.xhtml
INFO AJAX AFTER APPLY_REQUEST_VALUES 2 for viewId=/any.xhtml
INFO AJAX BEFORE PROCESS_VALIDATIONS 3 for viewId=/any.xhtml
INFO AJAX AFTER PROCESS_VALIDATIONS 3 for viewId=/any.xhtml
INFO AJAX BEFORE UPDATE_MODEL_VALUES 4 for viewId=/any.xhtml
INFO AJAX AFTER UPDATE_MODEL_VALUES 4 for viewId=/any.xhtml
INFO AJAX BEFORE INVOKE_APPLICATION 5 for viewId=/any.xhtml
INFO AJAX AFTER INVOKE_APPLICATION 5 for viewId=/any.xhtml
INFO AJAX BEFORE RENDER_RESPONSE 6 for viewId=/any.xhtml
INFO AJAX AFTER RENDER_RESPONSE 6 for viewId=/any.xhtml
My template page :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<meta http-equiv="Cache-Control" content="no-store" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</h:head>
<h:body>
<div>
<h:panelGroup id="globalMessages">
<h:messages globalOnly="false" styleClass="messages" />
</h:panelGroup>
<ui:insert name="content" />
</div>
</h:body>
</html>
the composition page, enabling to choose a page to include :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" >
<ui:composition template="/layout/template.xhtml">
<ui:define name="content">
<h:form id="chooseForm">
<h:panelGrid columns="2">
<h:outputLabel value="Choose your page to include" />
<h:selectOneMenu id="pageList" value="#{anyPageBean.page}">
<f:selectItems value="#{anyPageBean.pageList}" var="w" itemValue="#{w}" itemLabel="#{w}" />
</h:selectOneMenu>
</h:panelGrid>
<h:commandButton id="show" value="Show page">
<f:ajax event="click" execute="@form" render=":panelForDynaPage :globalMessages" />
</h:commandButton>
</h:form>
<h:panelGroup id="panelForDynaPage">
<ui:include id="includeContenu" src="#{anyPageBean.page}" />
</h:panelGroup>
</ui:define>
</ui:composition>
</html>
the pilotNoTemplate.xhtml page :
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<f:metadata>
<f:viewParam id="b" name="id" value="#{pilotAction.id}" />
</f:metadata>
<f:event id="a" listener="#{pilotAction.prepare}" type="preRenderView" />
<h:form id="formPilot">
<h:panelGrid columns="2">
<h:outputLabel value="#{appMsg['pilot.firstname']}" />
<h:inputText id="firstname" label="#{appMsg['pilot.firstname']}" value="#{pilotHolder.pilot.firstname}"
required="true" />
<h:outputLabel value="#{appMsg['pilot.lastname']}" />
<h:inputText id="lastname" label="#{appMsg['pilot.lastname']}" value="#{pilotHolder.pilot.lastname}" />
<h:outputLabel value="#{appMsg['pilot.age']}" />
<h:inputText id="age" label="#{appMsg['pilot.age']}" value="#{pilotHolder.pilot.age}" required="true"
validator="#{pilotAction.validateAge}" />
</h:panelGrid>
<h:commandButton id="merge" action="#{pilotAction.doMerge}"
value="#{pilotHolder.pilot.id ne null ? appMsg['pilot.update'] : appMsg['pilot.create']}">
<f:ajax id="ajaxm" event="click" execute="@form" render=":panelForDynaPage :globalMessages" />
</h:commandButton>
</h:form>
</ui:composition>
I paid attention to gives "id" to every component in the xhtml page, since there are that kind of problems without it, is seems to be unsuffient in my case. any idea ?
I 've seen others having the same problem, did you find any solution ?
回答1:
This is caused by JSF spec issue 790, a bug which occurs in JSF 2.0/2.1 and is fixed in the upcoming JSF 2.2. Basically, when JSF ajax updates outside the current <h:form>
a component which in turn contains another <h:form>
component as child, then its view state won't be updated (this is an oversight). It would only be updated when you explicitly specify the form component in the ajax update. You could theoretically solve it by replacing <h:panelGroup id="panelForDynaPage">
by a <h:form id="panelForDynaPage">
, but this is technically the wrong markup.
You can use the following JS to fix this bug. This script will create the javax.faces.ViewState
hidden field for forms which did not retrieve any view state after ajax update.
var ie = /*@cc_on!@*/false;
jsf.ajax.addOnEvent(function(data) {
if (data.status == "success") {
var viewState = document.getElementsByName("javax.faces.ViewState")[0].value;
for (var i = 0; i < document.forms.length; i++) {
var form = document.forms[i];
if (!hasViewState(form)) {
var hidden = document.createElement(ie ? "<input name='javax.faces.ViewState'>" : "input");
hidden.setAttribute("type", "hidden");
hidden.setAttribute("name", "javax.faces.ViewState");
hidden.setAttribute("value", viewState);
hidden.setAttribute("autocomplete", "off");
form.appendChild(hidden);
}
}
}
});
function hasViewState(form) {
for (var i = 0; i < form.elements.length; i++) {
if (form.elements[i].name == "javax.faces.ViewState") {
return true;
}
}
return false;
}
来源:https://stackoverflow.com/questions/11608595/dynamicly-included-page-form-first-submit-fails