通过Ajax更新JSF组件后,JavaScript/jQuery事件侦听器不起作用

Tin*_*iny 8 javascript jquery jsf primefaces jsf-2.2

我正在<p:dataTable>filter(其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();
            }
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

此功能位于context/resources/default/js/digit_only_textfield.js.因此,它可以在XHTML页面上使用,如,

<h:outputScript library="default" name="js/digit_only_textfield.js"/>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

这个jQuery适用于id为id的过滤器,is但是当<p:dataTable>通过按下给定更新<p:commandButton>它时,它会停止运行.

如何在<p:dataTable>AJAX更新后使此功能正常工作?


引入了一个新的问题域:

PrimeFaces社区论坛上的这个问题和相应的回复仍然没有导致以下问题域的解决方法/解决方案.

如果一个错误的键被击中(即一个非数字键,退格除外,删除等)那么,数据表会被不必要地更新,这会导致一些昂贵的查询被激发到数据库上,这是完全没必要的,必须防止数据表从更新.

Bal*_*usC 9

流程如下:

  • 浏览器检索HTML输出.
  • 浏览器基于HTML标记填充HTML DOM树.
  • 完成后,浏览器会触发HTML DOM ready事件.
  • jQuery的$(document).ready()函数处理程序都被调用.
  • 您通过ID在DOM中找到一个元素,并keydown为其附加一个侦听器.
  • 在用户交互期间,将触发ajax请求,并使用ajax响应传递的新HTML元素更新HTML DOM树.
  • 其中,具有keydown侦听器的元素正是从HTML DOM树中删除,并被没有任何keydown侦听器的新元素替换.ready在ajax请求期间不会触发文档事件.永远不会重新调用您的ready处理程序.该keydown监听器永远不会重新连接.对最终用户来说,它确实看起来似乎"停止运作".

此特定情况的解决方案现在应该是显而易见的:keydown在完成ajax调用时显式重新附加侦听器.最简单的方法是提取将keydown侦听器附加到可重用函数中的工作并按如下方式触发:

function applyKeydownOnTableFilter() { 
    // ...
}

$(document).ready(applyKeydownOnTableFilter);
Run Code Online (Sandbox Code Playgroud)

所以你可以做一个:

<p:commandButton ... oncomplete="applyKeydownOnTableFilter()" />
Run Code Online (Sandbox Code Playgroud)

但是,对于每个单独的ajax命令/监听器而言,这是非常繁琐的,并且不是非常易于维护.更好的方法是采用不同的方式:使用jQuery $.on()代替.更换

$(document).ready(function() {
    $("#form\\:dataTable\\:id\\:filter").keydown(function(event) {
        // ...
    });
});
Run Code Online (Sandbox Code Playgroud)

通过

$(document).on("keydown", "#form\\:dataTable\\:id\\:filter", function(event) {
    // ...
});
Run Code Online (Sandbox Code Playgroud)

这样,keydown监听器实际上并不附加到感兴趣的元素上.相反,由于JavaScript的事件冒泡功能,keydown事件最终将到达$(document)- 它始终存在,并且通常在JSF ajax请求期间不会更改.一旦到达,$(document).on()就会触发,然后确定事件的来源并检查它是否与给定的选择器匹配,如果是,则调用该函数.这一切都不需要将keydown侦听器附加到物理元素,因此对HTML DOM树中是否删除/替换元素不敏感.

也可以看看:


那么,您是否也看到HTML DOM树和JSF组件树之间存在多少相似之处?