I'm executing the following jQuery function on <p:dataTable>
filter (whose id is id
) that allows users to enter only digits in the filter component.
$(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();
}
}
});
});
This function is placed under context/resources/default/js/digit_only_textfield.js
. Therefore, it can be used on XHTML pages like,
<h:outputScript library="default" name="js/digit_only_textfield.js"/>
The XHTML page looks like the following.
<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>
This jQuery works fine for the filter whose id is is
but when this <p:dataTable>
is updated by pressing the given <p:commandButton>
, it stops functioning.
How to make this function work after <p:dataTable>
is updated by AJAX?
A new problem domain introduced:
This question and corresponding replies on the PrimeFaces Community Forum still do not lead to a workaround/solution to the following problem domain.
if a wrong key is hit (i.e a non-digit key, except backspace, delete etc) then, the data table is updated unnecessarily that causes some costly queries to be fired upon the database which is completely unnecessary and the data table must be prevented from being updated.
The flow is as follows:
ready
event.$(document).ready()
function handlers are all invoked.keydown
listener to it.keydown
listener is removed from HTML DOM tree and replaced by a fresh new element without any keydown
listener. The document ready
event is not fired during ajax requests. Your ready handler is never re-invoked. The keydown
listener is never re-attached. To the enduser, it then indeed seemingly "stops functioning".The solution on this particular case should now be obvious: explicitly re-attach the keydown
listener on complete of ajax call. Most straightforward would be to extract the job of attaching the keydown
listener into a reusable function and fire it as follows:
function applyKeydownOnTableFilter() {
// ...
}
$(document).ready(applyKeydownOnTableFilter);
So that you can just do a:
<p:commandButton ... oncomplete="applyKeydownOnTableFilter()" />
But this is quite tedious to repeat for every single ajax command/listener and not very maintenance friendly. Better is to approach it differently: use jQuery's $.on()
instead. Replace
$(document).ready(function() {
$("#form\\:dataTable\\:id\\:filter").keydown(function(event) {
// ...
});
});
by
$(document).on("keydown", "#form\\:dataTable\\:id\\:filter", function(event) {
// ...
});
This way the keydown
listener isn't actually attached to the element of interest. Instead, thanks to the event bubbling feature of JavaScript, the keydown event will ultimately reach the $(document)
— which is always present and usually not changed during JSF ajax requests. Once reached, the $(document).on()
is triggered, which will then determine the source of the event and check it if matches the given selector and if so, then invoke the function. This all without the need to attach the keydown
listener to the physical element and thus not sensitive to whether the element is removed/replaced in the HTML DOM tree.
By the way, do you also see how much similarities there are between HTML DOM tree and JSF component tree?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With