您可以使用以下脚本来修复Mojarra 2.0/2.1/2.2的bug(注意:这在MyFaces中不会表现出来)。此脚本将为未在ajax更新后检索任何视图状态的表单创建
javax.faces.ViewState
隐藏字段。
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 {
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'>");
} 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:body>
内包含它,如下所示:<h:outputScript name="some.js" target="head">
。如果不能保证所涉及的页面使用JSF <f:ajax>
,以触发自动包含jsf.js
,那么您可能需要在jsf.ajax.addOnEvent()
调用之前添加一个额外的if(typeof jsf !== 'undefined')
检查,或者通过以下方式显式地包含它:
<h:outputScript library="javax.faces" name="jsf.js" target="head" />
请注意,jsf.ajax.addOnEvent
仅适用于标准的JSF <f:ajax>
,而不适用于例如PrimeFaces <p:ajax>
或<p:commandXxx>
,因为它们在底层使用jQuery进行操作。要同时处理PrimeFaces ajax请求,请添加以下内容:
$(document).ajaxComplete(function(event, xhr, options) {
if (typeof xhr.responseXML != 'undefined') {
fixViewState(xhr.responseXML);
}
}
更新 如果你正在使用JSF实用库OmniFaces,那么很好知道,自1.7版本以来,上面的内容已经成为OmniFaces的一部分。只需要在<h:body>
中声明以下脚本即可。还可以参见演示文稿.
<h:body>
<h:outputScript library="omnifaces" name="fixviewstate.js" target="head" />
...
</h:body>
setAttribute("name", value)
对于输入元素不起作用,这正是为什么首先需要这个hack的原因。另请参见例如http://webbugtrack.blogspot.com/2007/10/bug-235-createelement-is-broken-in-ie.html。 - BalusC- osmingo