This is related to JSF spec issue 790 which boils down to that ajax-updating some component which in turn contains one or more <h:form>
components doesn't properly update the new view state identifier of those forms.
This issue is fixed in the upcoming JSF 2.2, but until then you've to do with the following JavaScript based workaround.
jsf.ajax.addOnEvent(function(data) {
if (data.status == "success") {
var viewState = getViewState(data.responseXML);
if (viewState) {
for (var i = 0; i < document.forms.length; i++) {
var form = document.forms[i];
if (!hasViewState(form)) {
createViewState(form, viewState);
}
}
}
}
});
function getViewState(responseXML) {
var updates = responseXML.getElementsByTagName("update");
for (var i = 0; i < updates.length; i++) {
var update = updates[i];
if (update.getAttribute("id") == "javax.faces.ViewState") {
return update.firstChild.nodeValue;
}
}
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);
}
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 uses JSF <f:ajax>
, then you might want to add an additional if (typeof jsf !== 'undefined')
check before jsf.ajax.addOnEvent()
call.
The JSF component library PrimeFaces has already solved this issue in its core ajax engine, so if you happen to use it already, you might want to replace all <f:ajax>
links/buttons by the PrimeFaces ones.
See also: