xhr.send() does not trigger ajaxComplete/ajaxSuccess, but $.get does. Why? - javascript

Imagine I have these three functions:
$( document ).ajaxSuccess(function( event, xhr, settings ) {
console.log('ajaxSuccess fired');
});
function doCall1 () {
var xhr = new XMLHttpRequest();
xhr.open('get', 'someurl.com', true);
xhr.send();
}
function doCall2 (){
$.get('someurl.com');
}
When I call doCall1, ajaxSuccess does not fire. However, when I call doCall2, ajaxSuccess does fire.
I understand this is related to the fact jQuery is in fact using a callback function to various methods of $.ajax() rather than looking at onreadystatechange / readyState of the XMLHttpRequest (correct me if I'm off the mark), but I still don't completely understand.
Can someone give me a quick explanation or direct me to some docs that'd get me the rest of the way to getting this?

As others have noted, ajaxSuccess and ajaxComplete are non-native events added by jQuery. If for some reason you wanted interop between jQuery and vanilla js, you could dispatch the events yourself (with the caveat that browser support for CustomEvent is limited):
var event = new CustomEvent("ajaxComplete");
document.dispatchEvent(event);

Thats because the ajaxSuccess and ajaxComplete methods are part of jQuery and they are only triggered by the jQuery functions.
XMLHttpRequest is a native javascript object and its not related with jQuery.

The code for triggering ajaxSuccess/ajaxComplete are written in the end of $.ajax(), $.get(), $.post(), etc. The above events are related to jQuery and the $.ajax(), $.get(), $.post() functions are jQuery functions.
The XHR is native JavaScript and is no way related to jQuery.

the one thing is the jQuery object having deferrers and the other one a native JavaScript object, where you have to attach a callback yourself and may forward it to the ajaxSuccess of jQuery (jQ wraps the native XMLRequest object and does that).

Related

How can I monitor Backbone ajax requests?

I thought this would be easy b.c. Backbone uses jQuery and has a single access point I thought I could just do this:
Backbone.ajax = function() {
var xhr = Backbone.$.ajax.apply(Backbone.$, arguments);
// xhr.addEventListener("loadend", loadEnd);
return xhr;
};
but for some reason I can not load an event listener to the xhr object as I normally do.
I get an error stating that addEventListener is not a function.
See jqXHR:
The jQuery XMLHttpRequest (jqXHR) object returned by $.ajax() as of jQuery 1.5 is a superset of the browser's native XMLHttpRequest object.
It is not exactly the native XMLHttpRequest, so it might not behave exactly like the native one. There is no guarantee that it exposes methods like addEventListener unless it's documented. If you want to set something globally it's safer to use jquery.ajaxsetup

How to manully trigger an ajaxComplete event

Using Jquery I need to trigger a ajaxComplete event.
At the moment I'm using this code with no success
$.getJSON(assetUrl, function (data) {
...
$.trigger("ajaxComplete");
With Error:
TypeError: 'undefined' is not a function (evaluating '$.trigger("ajaxComplete")')
Any idea what I'm doing wrong? Thanks
The ajaxCompleted event is fired on the DOM, and you will need to call the trigger method on a jQuery wrapper element: $(document).trigger(...), for example.
There is not static function "trigger" on the jQuery object (that's what the error message is telling you), you might use $.event.trigger - though I fear that's internal.
However, you won't need to do it manually; getJSON does trigger the event itself. For aborting a running ajax request, see the abort method of XHR objects.
You can define a global jQuery ajaxComplete (and ajaxError) function that will run on document ready and after every completed ajax request. You can define the ajaxComplete function on the intial page load (or whenever really) like this:
$(function(){
$(document).ajaxComplete(function(){
// on complete code
}).ajaxError(function(){
// on error code
});
});
To call this event handler at any time, just execute the following:
$(document).triggerHandler('ajaxComplete');
If anybody else is looking at this, the correct way to manually trigger ajaxComplete is $(document).trigger('ajaxComplete', [xhr, settings]);
It's probably important to pass the xhr object to the ajaxComplete trigger event, as the event handler might need it.
However, you only need this, if you're not making your requests through jquery, since jquery handles this automatically for you.

Spine javascript unable to unbind proxied callbacks

I am using spine javascript library for a standalone javascript application.
I heavily use the publisher/subscriber model and bind proxied callbacks to spine models.
When I try to unbind a proxied callback, it doesnt unbind it. This happens only with proxied callbacks.
A demo code
var Listener = Spine.Model.sub({
onChange : function(){this.log("Hooray!!")},
log:function(msg){console.log("Rxed event"+msg);},
bind: function(){SomeModel.bind("onChange",this.proxy(this.onChange));},
unBind:function(){SomeModel.unbind("onChange",this.proxy(this.onChange));}
});
var listener = new Listener();
when listener.bind() is called it binds it correctly and callbacks are correct.
but when listener.unBind() is called, the unbind doesnt happen.
If the callback was not proxied, it works but I need the correct context for the callback and so I need to proxy it.
Any help would be greatly appreciated.
You should do Spine.Class.sub since you don't need a model.
Secondly, change the unbind to: SomeModel.unbind("onChange");.
This way all callbacks are cleared. But you are right ... if you wrap the unbind with or without the proxy call it won't work. So I hope you don't have a need to unbind specific callbacks.
I made a jsfiddle to easily test it:
http://jsfiddle.net/SpoBo/cmUmT/2/
edit:
http://jsfiddle.net/SpoBo/cmUmT/3/
By using underscore's bindAll functionality it works. I guess the proxy does something odd which prevents the unbind function from successfully comparing callbacks.
http://jsfiddle.net/SpoBo/cmUmT/7/
It's recommended to use CoffeeScript though to write Spine and CS has a solution of itself for this problem. Just use the 'fat arrows'. However, if you can't use CS you can just use the code that CS generates. I solved it this way in version 7.
Basically, it creates a __bind function which returns a proxied function from a closure.
After that you override the original function with the proxied function.
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
someObject.onChange = __bind(someObject.onChange, someObject);
And now onChange will always be called from the context of someObject. Pretty cool stuff! But check the jsFiddle for a working demo.

Clearing a jquery document.ready() call

How do I clear out anonymous functions that are set to trigger via a jQuery document.ready() call?
For example:
<script type="text/javascript">
//some code sets a doc ready callback
$(document).ready(function ()
{
alert('ready');
});
//my attempt to prevent the callback from happening
window.onload = null;
$(document).unbind("ready");
</script>
The alert happens regardless of my attempts to circumvent it. Is there any way to do this?
You'd probably get the most appropriate answer if you described what problem you're really trying to solve.
jQuery doesn't have a publicly documented way to undo or block document.ready() handlers. If you control the code, you can use a global variable and a conditional like this:
var skipReady = false;
$(document).ready(function ()
{
if (!skipReady) {
alert('ready');
}
});
// skip the document.ready code, if it hasn't already fired
skipReady = true;
Or, if you want to hack into jQuery a bit (beyond the documented interfaces), you can do this:
$(document).ready(function() {
alert("ready");
});
// stop the ready handler
$.isReady = true;
You can see this last one work here: http://jsfiddle.net/jfriend00/ZjH2k/. This works because jQuery uses the property: $.isReady to keep track of whether it has already fired the ready handlers or not. Setting it to true makes it think it has already fired them so it won't every do it again.
This works:
$(document).bind("ready", function () { alert("hey!"); });
$(document).unbind("ready");
Seems like a bug to me - all other events in jQuery are able to be unbound. Omitting this one is inconsistent.
Not a direct answer as to the omission, but here's some related info from jQuery docs:
All three of the following syntaxes are equivalent:
$(document).ready(handler)
$().ready(handler) (this is not recommended)
$(handler)
There is also $(document).bind("ready", handler). This behaves similarly to the ready method but with one exception: If the ready event has already fired and you try to .bind("ready") the bound handler will not be executed. Ready handlers bound this way are executed after any bound by the other three methods above.
$(document).ready() is dependent on the onLoad event which is triggered by the browser meaning you can not prevent it from happening. If the alert() is determined by some condition then I would use an if/else statement to decide whether it is called.
Super old question, but came across the need to do this recently to prevent document.ready code I didn't control from running in certain instances. This can be achieved by proxying jQuery's ready function, rather like a test spy. The following will work:
var ready = $.prototype.ready;
// proxy the ready function
$.prototype.ready = function ( fn, allowed ) {
allowed = allowed || false;
if ( allowed ) {
ready.call( this, fn );
}
};
All calls to $( document ).ready will now be ignored. You can override this behaviour by passing true as the second argument: $( document ).ready( fn, true )

How can I execute a JavaScript function after Page Load is completed?

How can I execute a JavaScript function after Page Load is completed?
Use the onload event like this:
window.onload = function(){
// your code here.......
};
To get your onload handler to work cleanly in all browsers:
if (addEventListener in document) { // use W3C standard method
document.addEventListener('load', yourFunction, false);
} else { // fall back to traditional method
document.onload = yourFunction;
}
See http://www.quirksmode.org/js/events_advanced.html for more detail
Most JavaScript frameworks (e.g. jQuery, Prototype) encapsulate similar functionality to this.
For example, in jQuery, passing a function of your own to the core jQuery function $() results in your function being called when the page’s DOM is loaded. See http://api.jquery.com/jQuery/#jQuery3.
This occurs before the onload event fires, as onload waits for all external files like images to be downloaded. Your JavaScript probably only needs the DOM to be ready; if so, this approach is preferable to waiting for onload.
Event.observe(window, "onload", yourFunction);

Categories