h:commandButton/h:commandLink 在第一次单击时不起作用,仅在第二次单击时起作用 [英] h:commandButton/h:commandLink does not work on first click, works only on second click

查看:22
本文介绍了h:commandButton/h:commandLink 在第一次单击时不起作用,仅在第二次单击时起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We have an ajax navigation menu which updates a dynamic include. The include files have each their own forms.

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

它工作正常,但包含文件中的任何命令按钮在第一次单击时都不起作用.它仅适用于第二次点击.

It works correctly, but any command button in the include file doesn't work on first click. It works only on second click and forth.

我发现了这个问题 commandButton/commandLink/ajax action/listener method未调用或输入值未更新,我的问题在第 9 点中描述.我知道我需要在 的包含中明确包含 的 ID 来解决它.>

I found this question commandButton/commandLink/ajax action/listener method not invoked or input value not updated and my problem is described in point 9. I understand that I need to explicitly include the ID of the <h:form> in the include in the <f:ajax render> to solve it.

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

然而,在我的情况下,表单 ID 事先并不知道.此外,此表单最初将无法在上下文中使用.

In my case, however, the form ID is not known beforehand. Also this form will not be available in the context initally.

上述情况有什么解决办法吗?

Is there any solution to the above scenario?

推荐答案

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

You can use the following script to fix the Mojarra 2.0/2.1/2.2 bug (note: this doesn't manifest in MyFaces). This script will create the javax.faces.ViewState hidden field for forms which did not retrieve any view state after ajax update.

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

只需将其作为 包含在 错误页面.如果您不能保证有问题的页面使用 JSF <f:ajax>,这会触发 jsf.js 的自动包含,那么您可能想要在 jsf.ajax.addOnEvent() 调用之前添加额外的 if (typeof jsf !== 'undefined') 检查,或者通过

Just include it as <h:outputScript name="some.js" target="head"> inside the <h:body> of the error page. If you can't guarantee that the page in question uses JSF <f:ajax>, which would trigger auto-inclusion of jsf.js, then you might want to add an additional if (typeof jsf !== 'undefined') check before jsf.ajax.addOnEvent() call, or to explicitly include it by

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

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

Note that jsf.ajax.addOnEvent only covers standard JSF <f:ajax> and not e.g. PrimeFaces <p:ajax> or <p:commandXxx> as they use under the covers jQuery for the job. To cover PrimeFaces ajax requests as well, add the following:

$(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);
    }
}

<小时>

更新如果您正在使用 JSF 实用程序库 OmniFaces,很高兴知道以上已从 1.7 成为 OmniFaces 的一部分.只需在 中声明以下脚本即可.另请参阅展示.


Update if you're using JSF utility library OmniFaces, it's good to know that the above has since 1.7 become part of OmniFaces. It's just a matter of declaring the following script in the <h:body>. See also the showcase.

<h:body>
    <h:outputScript library="omnifaces" name="fixviewstate.js" target="head" />
    ...
</h:body>

这篇关于h:commandButton/h:commandLink 在第一次单击时不起作用,仅在第二次单击时起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆