h:commandButton/h:commandLink不适用于第一次点击,仅适用于第二次点击 [英] h:commandButton/h:commandLink does not work on first click, works only on second click
问题描述
我们有一个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方法未调用或输入值未更新,我的问题在第9点中进行了描述.
我了解我需要在<f:ajax render>
的include中明确包含<h:form>
的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);
}
}
}
只需将其作为<h:outputScript name="some.js" target="head">
包含在错误页面的<h:body>
中即可.如果您不能保证所讨论的页面使用的是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 <f:ajax>
,而不涵盖PrimeFaces <p:ajax>
或<p:commandXxx>
,因为它们在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的一部分.只需在<h:body>
中声明以下脚本即可.另请参见展示柜.
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屋!