Dynamicly included page form first submit fails

安稳与你 提交于 2019-12-08 05:44:55

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!