25

I have something like:

<p:inputText...>
    <p:ajax event="keyup" update="somefield" listener="#{someBean.doSomething}"/>
</p:inputText>

But I don't want to do an Ajax request on every keypress, I would like to do the request a half second after the user stops writing.

I have seen this problem solved in jQuery in another question: How to delay the .keyup() handler until the user stops typing?

I would like to know if it's possible to do this on primefaces or how adapt the solution from the jQuery question.
I'm using PrimeFaces 3.0.M4.
Thank you in advance.

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Roteke
  • 663
  • 2
  • 9
  • 12

4 Answers4

25

If using Primefaces 5.x, there's a delay attribute in the p:ajax tag for this purpose. So it's done like this:

<p:inputText...>
    <p:ajax event="keyup" delay="1000" listener="#{someBean.doSomething}"
        update="somefield" process="@this" />
</p:inputText>

If not, you could achieve it using f:ajax instead of p:ajax (yes, it works with p:inputText, too). f:ajax has added support for queue control starting from JSF 2.2. So the code looks like:

<p:inputText...>
    <f:ajax event="keyup" delay="1000" listener="#{someBean.doSomething}"
        render="somefield" execute="@this" />
</p:inputText>

See also:

Aritz
  • 30,971
  • 16
  • 136
  • 217
  • does `f:ajax` support all events that every PrimeFaces component has, or are there limitations? – Kukeltje Aug 27 '15 at 10:17
  • @Kukeltje, not sure about that. Theoretically, `p:ajax` is a more powerful implementation, but the components should work with `f:ajax` as well. Anyway, this answer is the only drawback for not using `f:ajax` in this concrete case, IMO. – Aritz Aug 27 '15 at 10:43
  • Tried to add 'delay' to `p:ajax` to? According to the docs, it exists. – Kukeltje Aug 27 '15 at 12:17
  • @Kukeltje, you're right. It was added for 5.x. I'm going to update my answer ;-) – Aritz Aug 27 '15 at 12:37
  • 1
    Now I want half the reputation ;-) – Kukeltje Aug 27 '15 at 12:57
  • Maybe it is better to edit the already accepted answer and split it in two... pre 5.0 and post... – Kukeltje Aug 27 '15 at 13:03
18

Why don't you use PrimeFaces' RemoteCommand component?

It gives you a global Javascript function, that you can call from wherever whenever you want. And it lets you call the managed-bean method and it has the update attribute for partial update.

<p:inputText id="input" />

<h:form>
    <p:remoteCommand name="sendAjaxical" update="somefield" action="#{someBean.doSomething}"/>
</h:form>

Register event handler, I borrowed the following from the same answer you posted:

var delay = (function() {
    var timer = 0;
    return function(callback, ms) {
        clearTimeout (timer);
        timer = setTimeout(callback, ms);
    };
})();


jQuery("#input").keyup(function() {
    delay(function() { sendAjaxical(); }, 2000); //sendAjaxical is the name of remote-command
});
Community
  • 1
  • 1
Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142
  • 1
    This worked nicely, I didn't know about remoteComand. I had to replace the jQuery part of the script with something like: `function ajaxDelay(){ delay(function() { sendAjaxical(); }, 2000);}` And call it like this `` Thank you very much! – Roteke Dec 07 '11 at 00:05
1

A quick hack would be adding a delay in onstart of the p:ajax. Define the following function somewhere in your javascript:

function keyupDelay(request, cfg, delay) {
    delay = delay || 2000;// if no delay supplied, two seconds are the default seconds between ajax requests
    setTimeout(function() {
        cfg.onstart = null;
        request.send(cfg)
    }, delay);
    return false;
}

Basically that function triggers the ajax request in a certain timeout while returning false for the immediate one, and emptying the onstart on that timedout request in order not to stuck in a nasty loop.

Then on the p:ajax:

<p:ajax event="keyup" onstart="return keyupDelay(this, cfg)" />

The delay parameter is optional here, by default it's 2 seconds.

Hatem Alimam
  • 9,968
  • 4
  • 44
  • 56
1

You cannot use the Primefaces Ajax Component, if you chose the jquery/javascript solution. You would have to implement your own javascript function (with ajax/xmlHttpRequest support) and trigger that function after half a second.

But there is another solution, a workaround: you could use an autocomplete component and use 3 helpful attributes: valueChangeListener(A method expression that refers to a method for handling a valuchangeevent - you use that instead of completeMethod because you don't need the returning suggestions), queryDelay (Delay to wait in milliseconds before sending each query to the server) and minQueryLength (Number of characters to be typed before starting to query - if you don't want to start the ajax request after just one character typed).

I hope you will find this solution quiet interesting...Please see the autocomplete component in action here( http://www.primefaces.org/showcase-labs/ui/autocompleteHome.jsf ) and you can find out more by reading the Primefaces User Guide for 3.0.M4.

spauny
  • 4,976
  • 9
  • 44
  • 61
  • This worked to call the bean method with the delay I wanted, but it doesn't have update (which I require), and neither does a submit of the value at the time the valueChangeListener is executed. But the answer helped me a to find other solutions. Thank you very much. – Roteke Dec 07 '11 at 00:00