h:commandButton/h:commandLink 在第一次单击时不起作用,仅在第二次单击时起作用

2024-01-02

我们有一个 ajax 导航菜单,可以更新动态包含。每个包含文件都有自己的形式。

<h:form>
    <h:commandButton value="Add" action="#{navigator.setUrl('AddUser')}">
        <f:ajax render=":propertiesArea" />
    </h:commandButton>
</h:form>
<h:panelGroup id="propertiesArea" layout="block">
    <ui:include src="#{navigator.selectedLevel.url}" />
</h:panelGroup>

它工作正常,但包含文件中的任何命令按钮在第一次单击时都不起作用。它仅在第二次单击和前后单击时有效。

我发现这个问题commandButton/commandLink/ajax 操作/侦听器方法未调用或输入值未更新 https://stackoverflow.com/questions/2118656/hcommandlink-hcommandbutton-is-not-being-invoked/2120183#2120183我的问题已在第 9 点中描述。 我了解我需要明确包含 ID<h:form>在 包括 在<f:ajax render>来解决它。

<f:ajax render=":propertiesArea :propertiesArea:someFormId" />

然而,就我而言,表单 ID 事先并不知道。此外,该表格最初在上下文中不可用。

对于上述场景有什么解决办法吗?


您可以使用以下脚本来修复 Mojarra 2.0/2.1/2.2 错误(注意:这不会在 MyFaces 中体现)。该脚本将创建javax.faces.ViewStateajax 更新后未检索任何视图状态的表单的隐藏字段。

jsf.ajax.addOnEvent(function(data) {
    if (data.status == "success") {
        fixViewState(data.responseXML);
    }
});

function fixViewState(responseXML) {
    var viewState = getViewState(responseXML);

    if (viewState) {
        for (var i = 0; i < document.forms.length; i++) {
            var form = document.forms[i];

            if (form.method == "post") {
                if (!hasViewState(form)) {
                    createViewState(form, viewState);
                }
            }
            else { // PrimeFaces also adds them to GET forms!
                removeViewState(form);
            }
        }
    }
}

function getViewState(responseXML) {
    var updates = responseXML.getElementsByTagName("update");

    for (var i = 0; i < updates.length; i++) {
        var update = updates[i];

        if (update.getAttribute("id").match(/^([\w]+:)?javax\.faces\.ViewState(:[0-9]+)?$/)) {
            return update.textContent || update.innerText;
        }
    }

    return null;
}

function hasViewState(form) {
    for (var i = 0; i < form.elements.length; i++) {
        if (form.elements[i].name == "javax.faces.ViewState") {
            return true;
        }
    }

    return false;
}

function createViewState(form, viewState) {
    var hidden;

    try {
        hidden = document.createElement("<input name='javax.faces.ViewState'>"); // IE6-8.
    } catch(e) {
        hidden = document.createElement("input");
        hidden.setAttribute("name", "javax.faces.ViewState");
    }

    hidden.setAttribute("type", "hidden");
    hidden.setAttribute("value", viewState);
    hidden.setAttribute("autocomplete", "off");
    form.appendChild(hidden);
}

function removeViewState(form) {
    for (var i = 0; i < form.elements.length; i++) {
        var element = form.elements[i];
        if (element.name == "javax.faces.ViewState") {
            element.parentNode.removeChild(element);
        }
    }
}

只需将其包含为<h:outputScript name="some.js" target="head">在 - 的里面<h:body>的错误页面。如果您不能保证有问题的页面使用 JSF<f:ajax>,这将触发自动包含jsf.js,那么您可能需要添加一个额外的if (typeof jsf !== 'undefined')之前检查jsf.ajax.addOnEvent()调用,或者显式包含它

<h:outputScript library="javax.faces" name="jsf.js" target="head" />

注意jsf.ajax.addOnEvent仅涵盖标准 JSF<f:ajax>而不是例如PrimeFaces<p:ajax> or <p:commandXxx>因为他们在幕后使用 jQuery 来完成这项工作。要覆盖 PrimeFaces ajax 请求,请添加以下内容:

$(document).ajaxComplete(function(event, xhr, options) {
    if (typeof xhr.responseXML != 'undefined') { // It's undefined when plain $.ajax(), $.get(), etc is used instead of PrimeFaces ajax.
        fixViewState(xhr.responseXML);
    }
}

Update如果您使用 JSF 实用程序库OmniFaces http://omnifaces.org,很高兴知道上述内容自 1.7 起已成为 OmniFaces 的一部分。只需在以下声明中声明以下脚本即可<h:body>。另请参阅showcase http://showcase.omnifaces.org/scripts/FixViewState.

<h:body>
    <h:outputScript library="omnifaces" name="fixviewstate.js" target="head" />
    ...
</h:body>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

h:commandButton/h:commandLink 在第一次单击时不起作用,仅在第二次单击时起作用 的相关文章

随机推荐