通过 ajax 渲染其他表单会导致其视图状态丢失,如何将其添加回来?

Posted

技术标签:

【中文标题】通过 ajax 渲染其他表单会导致其视图状态丢失,如何将其添加回来?【英文标题】:Rendering other form by ajax causes its view state to be lost, how do I add this back? 【发布时间】:2011-12-10 01:50:11 【问题描述】:

我有

<h:form>
    <h:commandLink action="#my_fake_ajax_link">
        <h:outputText value="Link" />
        <f:ajax render=":mydiv" />
    </h:commandLink>
</h:form>

<h:panelGroup layout="block" id="mydiv">
    <h:form>
        <h:commandLink action="#mybean.delete(0)">
            <h:outputText value="Here" />
            <f:ajax render="@form" />
        </h:commandLink>
    </h:form>
</h:panelGroup>

当我点击一次“my_fake_ajax_link”时,我必须点击两次“删除”链接。这只是一个例子。我没有这个真实案例。我在一个页面上有多个表单,我不能将所有表单都添加到一个表单中。

我检查了问题所在:

当您单击“my_fake_ajax_link”时,mydiv 会按照应有的方式使用 ajax 进行刷新。 ajax 上刷新表单的 ViewState 丢失。

如何添加 ViewState?我怎样才能使它工作而不使用仅一种形式?对我来说,这看起来像是一个 JSF 错误。我不想用

自动刷新那个 div
jQuery("#mydiv").load(document.location.href);

但在最坏的情况下我会这样做。

【问题讨论】:

【参考方案1】:

这是处理 ajax 响应的 JSF 自动包含的 jsf.js 库中的一个已知问题。另请参阅JSF spec issue 790,它已在即将发布的 JSF 2.3 中修复。同时,在 JSF 2.0/2.1/2.2 中,您必须在 render 属性内显式指定另一个 &lt;h:form&gt; 的 ID 以触发正确添加视图状态。

<h:form>
    <h:commandLink action="#my_fake_ajax_link">
        <h:outputText value="Link" />
        <f:ajax render=":mydiv :mydivForm" />
    </h:commandLink>
</h:form>

<h:panelGroup layout="block" id="mydiv">
    <h:form id="mydivForm">
        <h:commandLink action="#mybean.delete(0)">
            <h:outputText value="Here" />
            <f:ajax render="@form" />
        </h:commandLink>
    </h:form>
</h:panelGroup>

不,这不会导致 ajax 响应中的任何开销或标记重复。或者,使用OmniFaces fixviewstate.js

另见:

Communication in JSF 2.0 - Ajax rendering of content which contains another form h:commandButton/h:commandLink does not work on first click, works only on second click

【讨论】:

非常感谢!!!我在谷歌上没有找到那个链接..即使经过长时间的搜索...... 很遗憾这还没有进入 JSF 2.2。让我们再等一两年修复它...... @mel:OmniFaces 救援:showcase.omnifaces.org/scripts/FixViewState【参考方案2】:

解决方法:

首先,您需要为发送 ajax 请求的按钮设置一个 onevent 处理程序:

<h:form id="newComment">
    <h:commandButton id="saveNewComment" action="#postBean.actionSaveNewCommentAjax" value="#rb['speichern']">
        <f:ajax execute="@form" render=":commentsBox" onevent="function(data)  fixOtherFormsViewState(data, 'newComment') " />
    </h:commandButton>
</h:form>

然后你需要声明这个 javascript 方法,它将采用正确的 viewState 值并将其添加到所有没有它的表单:

<h:outputScript>
function fixOtherFormsViewState(data, goodFormId) 
    if (data.status != "success") 
        return;
    

    var viewState = jQuery("#" + goodFormId + " input[name='javax.faces.ViewState']").val();
    jQuery("form:not(:contains(input[name='javax.faces.ViewState']))").each(function (idx, elem) 
        var form = jQuery(elem);
        var input = jQuery("&lt;input type='hidden' name='javax.faces.ViewState' /&gt;").val(viewState);
        form.append(input);
    );

</h:outputScript>

【讨论】:

以上是关于通过 ajax 渲染其他表单会导致其视图状态丢失,如何将其添加回来?的主要内容,如果未能解决你的问题,请参考以下文章

渲染 json 未显示在 rails 4 的视图中

当表单滚动到屏幕外时,每个表单字段的状态会丢失吗?

禁用文本框丢失视图状态

如何刷新表单中的下拉字段而不使用ajax刷新整个表单?

JSF Ajax 渲染使用 Jquery Mobile 丢失 CSS

(火狐浏览器)前端以FormData类形成表单(含文件),通过ajax提交,PHP后端iconv()报“文件名含有非法字符”且POST中的‘Ttitle’丢失