通过 Ajax 更新 JSF 组件后,JavaScript/jQuery 事件侦听器不起作用
Posted
技术标签:
【中文标题】通过 Ajax 更新 JSF 组件后,JavaScript/jQuery 事件侦听器不起作用【英文标题】:JavaScript/jQuery event listeners do not work after JSF component is updated via Ajax 【发布时间】:2013-12-12 06:40:41 【问题描述】:我正在<p:dataTable>
过滤器(其 id 为 id
)上执行以下 jQuery 函数,该函数允许用户在过滤器组件中仅输入数字。
$(document).ready(function()
$("#form\\:dataTable\\:id\\:filter").keydown(function(event)
//Allow: tab, escape, and enter
if(event.keyCode===9||event.keyCode===27||event.keyCode===13||
//Allow: Ctrl+A, Ctrl+C
(event.keyCode===65&&event.ctrlKey===true)||(event.keyCode===67&&event.ctrlKey===true)||
//Allow: home, end, left, right
(event.keyCode>=35&&event.keyCode<=39))
//let it happen, don't do anything
event.preventCapture();
return;
//backspace, delete
else if(event.keyCode===46||event.keyCode===8)
return;
else//Ensure that it is a number and stop the keypress
if (event.shiftKey||(event.keyCode<48||event.keyCode>57)&&(event.keyCode< 96||event.keyCode>105))
//event.preventDefault();
event.preventCapture();
);
);
这个函数放在context/resources/default/js/digit_only_textfield.js
下。因此,它可以用于 Xhtml 页面,例如,
<h:outputScript library="default" name="js/digit_only_textfield.js"/>
XHTML 页面如下所示。
<h:outputScript library="default" name="js/digit_only_textfield.js"/>
<h:form id="form" prependId="true">
<!--PrimeFaces extension <pe:blockUI>-->
<p:remoteCommand name="updateTable" update="dataTable"/>
<p:panel id="panel">
<h:panelGrid id="panelGrid" columns="3" cellpadding="5">
<!--Some UIInput components-->
<p:commandButton id="btnSubmit"
update="panel"
onstart="PF('blockUIWidget').block();"
oncomplete="if(!args.validationFailed) updateTable();PF('blockUIWidget').unblock();"
actionListener="#bean.insert"
value="Save"/>
</h:panelGrid>
</p:panel>
<p:dataTable id="dataTable"
var="row"
value="#bean"
filterEvent="keydown"
...
... >
...
...
<p:dataTable>
<h:form>
这个 jQuery 对 id 为 is
的过滤器工作正常,但是当这个 <p:dataTable>
通过按下给定的<p:commandButton>
更新时,它停止运行。
<p:dataTable>
被 AJAX 更新后,如何使该功能生效?
引入了一个新的问题域:
This PrimeFaces 社区论坛上的问题和相应回复仍然无法解决以下问题。
如果按下了错误的键(即非数字键,退格键除外,请删除 等)然后,数据表被不必要地更新,导致一些 对数据库进行昂贵的查询,这完全是 不必要的并且必须防止更新数据表。
【问题讨论】:
在表格更新后,您是否尝试过再次运行 jQuerykeydown
函数?如果表格在更新时由 PrimeFaces 从头开始渲染,则 jQuery on event trigger 将被删除。
只是PrimeFaces数据表中的一个过滤事件-<p:dataTable>
,filterEvent="keydown"
的一个属性。
我不明白赏金和明显的新问题。
我本可以提出一个单独的问题,但除了问题中的块引用中的文本之外,大多数情况下情况相同。
这不是您自定义 jQuery 函数的全部意图吗?还是那部分不起作用?
【参考方案1】:
流程如下:
浏览器检索 HTML 输出。 浏览器根据 HTML 标记填充 HTML DOM 树。 完成后,浏览器触发 HTML DOMready
事件。
jQuery 的$(document).ready()
函数处理程序都被调用。
Yours 通过 ID 在 DOM 中找到一个元素,并将 keydown
侦听器附加到它。
在用户交互期间,会触发 ajax 请求,并使用 ajax 响应提供的新 HTML 元素更新 HTML DOM 树。
除其他外,具有keydown
侦听器的元素将从HTML DOM 树中删除,并替换为没有任何keydown
侦听器的新元素。在 ajax 请求期间不会触发文档 ready
事件。您的就绪处理程序永远不会重新调用。 keydown
监听器永远不会重新连接。对于最终用户来说,它确实看起来“停止运行”。
这种特殊情况的解决方案现在应该很明显了:在完成 ajax 调用时显式重新附加 keydown
侦听器。最直接的方法是将 keydown
侦听器附加到可重用函数中并按如下方式触发它:
function applyKeydownOnTableFilter()
// ...
$(document).ready(applyKeydownOnTableFilter);
这样你就可以做一个:
<p:commandButton ... oncomplete="applyKeydownOnTableFilter()" />
但是对于每个单独的 ajax 命令/侦听器重复这是非常乏味的,并且对维护不是很友好。更好的方法是采用不同的方法:改用 jQuery 的 $.on()
。替换
$(document).ready(function()
$("#form\\:dataTable\\:id\\:filter").keydown(function(event)
// ...
);
);
通过
$(document).on("keydown", "#form\\:dataTable\\:id\\:filter", function(event)
// ...
);
这样keydown
监听器实际上并没有附加到感兴趣的元素上。相反,由于 javascript 的事件冒泡特性,keydown 事件最终会到达$(document)
——它始终存在并且在 JSF ajax 请求期间通常不会更改。一旦到达,$(document).on()
就会被触发,然后它将确定事件的来源并检查它是否与给定的选择器匹配,如果是,则调用该函数。这一切都不需要将keydown
侦听器附加到物理元素,因此对元素是否在 HTML DOM 树中被删除/替换不敏感。
另见:
JSF/PrimeFaces ajax updates breaks jQuery event listener function bindings顺便问一下,您是否也看到 HTML DOM 树和 JSF 组件树之间有多少相似之处?
【讨论】:
一如既往的感谢。$.on()
的方法按预期工作。有一件小事,但是我无法弄清楚。在使用$.on()
时,如果按下了错误的键(即任何非数字键),则数据表会被不必要地更新,这会导致在数据库上执行一些代价高昂的查询,这是完全不必要的。当按下错误的键时,是否有任何解决方法可以防止数据表被更新。这应该由event.preventDefault();
单独完成,但事实并非如此。在问题中使用$(document).ready(function() );
时,这并没有发生。
哦,对了 :( PrimeFaces 不直接使用 onkeydown
属性,而是通过 jQuery 附加一个事件处理程序。这是在您的事件处理程序之前触发的。所以,基本上,你来晚了......对不起,你必须切换回ready
事件,以便首先附加你的事件。为了尽量减少oncomplete
的混乱,你可能想在一个页面中执行这项工作- <p:ajaxStatus oncomplete>
或 $.ajaxStop()
的广泛方式。
至于这个问题的具体要求,PrimeFaces 5.0(目前作为候选发布-RC1)自带了方便的数据表过滤器data table filters中有一个major enhancement。因此,可以完全消除对数据表过滤器的此类客户端验证:)以上是关于通过 Ajax 更新 JSF 组件后,JavaScript/jQuery 事件侦听器不起作用的主要内容,如果未能解决你的问题,请参考以下文章
JSF(Primefaces)通过ID更新几个元素的ajax
JSF 复合组件 <f:ajax> 包含未知 id - 无法在组件的上下文中找到它