Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I call a JavaScript function after every a4j AJAX response?

I am working on a web app using JSF w/Seam. I want to be able to call a JavaScript function after every ajax response. I'm looking for a way to do this without putting an oncomplete attribute on every commandLink/commandButton on every page.

I think there's a way to set up a servlet filter (interceptor? I get the terms confused) to inject the JS call into each response. I'm going to look into that. In the meantime, if anyone has any other suggestions, I'm all ears.

EDIT: I think the jQuery ajaxSuccess method might be the way to go here, but I'm not sure how to actually use it. I can't get anything to register. I basically want to add code to get any and all ajax requests from any source to call my JavaScript method on success. Can anyone show me the proper way to do this? I've tried a number of ways to do this, including adding jQuery("*").ajaxSuccess(function(){myFunction();}); to the bottom of my template xhtml file.

like image 526
iandisme Avatar asked Dec 21 '22 07:12

iandisme


2 Answers

Rewritten answer: see original answer in revision history

You could override the default send method of XMLHttpRequest with one that hijacks the readystatechange handler:

(function () 
{ 
    var xhrSend = XMLHttpRequest.prototype.send; 
    XMLHttpRequest.prototype.send = function  () 
     { 
        var handler = this.onreadystatechange; 
        this.onreadystatechange = function () 
        { 
            if (handler) {
                if (handler.handleEvent) handler.handleEvent.apply(xhr, arguments);
                else handler.apply(xhr, arguments);
            }
            if (this.readyState == 4) 
            { 
                // your oncomplete function here 
                this.onreadystatechange = handler; 
             } 
         }; 
        xhrSend.apply(this, arguments); 
    }; 
})(); 

Edit: The above function doesn't work with jQuery requests, and so potentially it could fail with other libraries as well. The revision below addresses the issue with a setTimeout hack to delay the code that overrides the handler. Of course, with jQuery, you can just use the .ajaxSuccess() global handler, but for other libraries with similar behavior, this would be useful.

(function() {
    function globalHandler() {
        if (this.readyState == 4) {
            // your oncomplete code here
        }
    }
    var xhrSend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send = function() {
        var xhr = this;
        if (xhr.addEventListener) {
            xhr.removeEventListener("readystatechange", globalHandler);
            xhr.addEventListener("readystatechange", globalHandler, false);
        }
        else {
            function readyStateChange() {
                if (handler) {
                    if (handler.handleEvent)
                        handler.handleEvent.apply(xhr, arguments);
                    else
                        handler.apply(xhr, arguments);
                }
                globalHandler.apply(xhr, arguments);
                setReadyStateChange();
            }
            function setReadyStateChange() {
                setTimeout(function() {
                    if (xhr.onreadystatechange != readyStateChange) {
                        handler = xhr.onreadystatechange;
                        xhr.onreadystatechange = readyStateChange;
                    }
                }, 1);
            }
            var handler;
            setReadyStateChange();
        }
        xhrSend.apply(xhr, arguments);
    };
})();

http://jsfiddle.net/gilly3/FuacA/5/
I tested this in IE7-9, and the latest versions of Chrome and FF

like image 131
gilly3 Avatar answered Jan 05 '23 22:01

gilly3


Since you are using RichFaces you can simply use this:

<a:status id="globalStatus" onstart="onRequestStart()" onstop="onRequestEnd()" />
like image 25
Martin Frey Avatar answered Jan 05 '23 22:01

Martin Frey