动态地包含的网页表单首先提交失败表单、网页、动态

2023-09-10 18:14:21 作者:野味儿仙女

我有动态地包含的页面

我的第一个页面有一个组合,从不同的页面选择要包括:

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>

在AnyPageBean只是给出背部的2以下页面之一:pilotNoTemplate.xhtml或pipo.xhtml

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");
}

当我选择页(PIPO页还)。

The pilotNoTemplate.xhtml appears correctly when i choose that page (the pipo page also).

但是,当我从pilotNoTemplate.xhtml提交表单,JSF认为,提交一个帖子里面就OK了, 但只有1阶段和第6阶段的跨越,为什么呢? 我有一个的PhaseListener展示阶段,它打印:

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>

在pilotNoTemplate.xhtml页:

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>

我重视赋予身份证在XHTML页面中的每个组件, 因为有那种没有它的问题,就是似乎unsuffient在我的情况。 任何想法?

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 ?

推荐答案

这是由 JSF规范问题790 ,发生在JSF 2.0 / 2.1,并固定在即将到来的JSF 2.2中的错误。基本上,当外界目前JSF AJAX更新&LT; H:形式GT; 的成分又包含另一个&LT; H:形式GT; 组件作为孩子,那么它的视图状态将不会更新(这是一个疏忽)。它只会更新时,您明确的AJAX更新指定表单组件。 panelGroup中的id =panelForDynaPage&GT; 由&LT; H:格式ID =panelForDynaPageH;你可以通过替换&LT理论上解决&GT; ,但是这在技术上是错误的标记

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.

您可以使用下面的JS来解决这个问题。该脚本将创建 javax.faces.ViewState 隐藏字段,而AJAX更新后未检索到任何视图状态表格。

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;
}