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

Jsf h:commandButton/h:commandLink在第一次单击时不起作用,仅在第二次单击时起作用,jsf,jsf-2,commandbutton,commandlink,Jsf,Jsf 2,Commandbutton,Commandlink,我们有一个ajax导航菜单,它更新了一个动态include。包含文件各有其自己的表单 <h:form> <h:commandButton value="Add" action="#{navigator.setUrl('AddUser')}"> <f:ajax render=":propertiesArea" /> </h:commandButton> </h:form> <h:panelGroup

我们有一个ajax导航菜单,它更新了一个动态include。包含文件各有其自己的表单

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

它工作正常,但第一次单击时,include文件中的任何命令按钮都不起作用。它只在第二次点击后才起作用

我发现了这个问题,第9点描述了我的问题。 我知道我需要在包含在
中明确包含
的ID来解决它

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

然而,在我的例子中,表单ID事先是未知的。此外,此表单在初始上下文中不可用


上述场景有什么解决方案吗?

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

jsf.ajax.addOnEvent(函数(数据){
如果(data.status==“成功”){
fixViewState(data.responseXML);
}
});
函数fixViewState(responseXML){
var viewState=getViewState(responseXML);
如果(视图状态){
对于(var i=0;i
只需将其作为
包含在错误页面的
中即可。如果您不能保证所讨论的页面使用JSF
,这将触发自动包含
JSF.js
,那么您可能需要添加一个额外的
If(typeof JSF!=“undefined”)
JSF.ajax.addOnEvent()
调用之前检查,或者通过


请注意,
jsf.ajax.addOnEvent
仅涵盖标准jsf
,而不包括PrimeFaces
,因为它们在作业的封面下使用jQuery。要同时涵盖PrimeFaces ajax请求,请添加以下内容:

$(文档).ajaxComplete(函数(事件、xhr、选项){
if(typeof xhr.responseXML!=“undefined”){//当使用普通的$.ajax()、$.get()等代替PrimeFaces ajax时,它是未定义的。
固定视图状态(xhr.responseXML);
}
}

更新如果您使用的是JSF实用程序库,很高兴知道上述内容自1.7版以来已成为OmniFaces的一部分。只需在
中声明以下脚本即可。另请参阅


...

感谢巴卢斯克,因为他的答案非常棒(和往常一样:)。但我必须补充一点,这种方法不适用于来自RichFaces4的ajax请求。他们在ajax方面有几个问题,其中之一是没有调用JSF ajax处理程序。因此,在使用RichFaces组件对包含表单的容器执行重新渲染时,不会调用fixViewState函数,并且会丢失ViewState

在中,他们说明了如何为“他们的”ajax请求注册回调(事实上,他们正在利用jQuery钩住所有ajax请求)。 但是使用它,我无法获得上面BalusC脚本用于获取ViewState的ajax响应

基于巴卢斯的修正,我得出了一个非常相似的修正。在浏览器处理ajax请求之前,我的脚本将当前页面上所有表单的所有ViewState值保存在映射中。更新DOM后,我尝试恢复以前保存的所有ViewState(对于现在缺少ViewState的所有表单)

继续:

jQuery(document).ready(function() {
    jQuery(document).on("ajaxbeforedomupdate", function(args) {
        // the callback will be triggered for each received JSF AJAX for the current page
        // store the current view-states of all forms in a map
        storeViewStates(args.currentTarget.forms);
    });
    jQuery(document).on("ajaxcomplete", function(args) {
        // the callback will be triggered for each completed JSF AJAX for the current page
        // restore all view-states of all forms which do not have one
        restoreViewStates(args.currentTarget.forms);
    });
});

var storedFormViewStates = {};

function storeViewStates(forms) {
    storedFormViewStates = {};
    for (var formIndex = 0; formIndex < forms.length; formIndex++) {
        var form = forms[formIndex];
        var formId = form.getAttribute("id");
        for (var formChildIndex = 0; formChildIndex < form.children.length; formChildIndex++) {
            var formChild = form.children[formChildIndex];
            if ((formChild.hasAttribute("name")) && (formChild.getAttribute("name").match(/^([\w]+:)?javax\.faces\.ViewState(:[0-9]+)?$/))) {
                storedFormViewStates[formId] = formChild.value;
                break;
            }
        }
    }
}

function restoreViewStates(forms) {
    for (var formIndexd = 0; formIndexd < forms.length; formIndexd++) {
        var form = forms[formIndexd];
        var formId = form.getAttribute("id");
        var viewStateFound = false;
        for (var formChildIndex = 0; formChildIndex < form.children.length; formChildIndex++) {
            var formChild = form.children[formChildIndex];
            if ((formChild.hasAttribute("name")) && (formChild.getAttribute("name").match(/^([\w]+:)?javax\.faces\.ViewState(:[0-9]+)?$/))) {
                viewStateFound = true;
                break;
            }
        }
        if ((!viewStateFound) && (storedFormViewStates.hasOwnProperty(formId))) {
            createViewState(form, storedFormViewStates[formId]);
        }
    }
}

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);
}
jQuery(文档).ready(函数(){
jQuery(document).on(“ajaxbeforedomupdate”,函数(args){
//将为当前页面的每个接收到的JSF AJAX触发回调
//将所有窗体的当前视图状态存储在地图中
StoreViewState(args.currentTarget.forms);
});
jQuery(document).on(“ajaxcomplete”,函数(args){
//将为当前页面的每个完成的JSF AJAX触发回调
//还原没有视图状态的所有窗体的所有视图状态
RestoreViewState(args.currentTarget.forms);
});
});
var storedFormViewStates={};
函数StoreViewState(表单){
StoredFormViewState={};
对于(var formIndex=0;formIndexjQuery(document).ready(function() {
    jQuery(document).on("ajaxbeforedomupdate", function(args) {
        // the callback will be triggered for each received JSF AJAX for the current page
        // store the current view-states of all forms in a map
        storeViewStates(args.currentTarget.forms);
    });
    jQuery(document).on("ajaxcomplete", function(args) {
        // the callback will be triggered for each completed JSF AJAX for the current page
        // restore all view-states of all forms which do not have one
        restoreViewStates(args.currentTarget.forms);
    });
});

var storedFormViewStates = {};

function storeViewStates(forms) {
    storedFormViewStates = {};
    for (var formIndex = 0; formIndex < forms.length; formIndex++) {
        var form = forms[formIndex];
        var formId = form.getAttribute("id");
        for (var formChildIndex = 0; formChildIndex < form.children.length; formChildIndex++) {
            var formChild = form.children[formChildIndex];
            if ((formChild.hasAttribute("name")) && (formChild.getAttribute("name").match(/^([\w]+:)?javax\.faces\.ViewState(:[0-9]+)?$/))) {
                storedFormViewStates[formId] = formChild.value;
                break;
            }
        }
    }
}

function restoreViewStates(forms) {
    for (var formIndexd = 0; formIndexd < forms.length; formIndexd++) {
        var form = forms[formIndexd];
        var formId = form.getAttribute("id");
        var viewStateFound = false;
        for (var formChildIndex = 0; formChildIndex < form.children.length; formChildIndex++) {
            var formChild = form.children[formChildIndex];
            if ((formChild.hasAttribute("name")) && (formChild.getAttribute("name").match(/^([\w]+:)?javax\.faces\.ViewState(:[0-9]+)?$/))) {
                viewStateFound = true;
                break;
            }
        }
        if ((!viewStateFound) && (storedFormViewStates.hasOwnProperty(formId))) {
            createViewState(form, storedFormViewStates[formId]);
        }
    }
}

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