jQuery ajax beforeSend shadows the `$.ajaxSetup` one, How to cascade it? - javascript

I'm using django-rest-framework.
And I have to add the X-CSRFToken header before every jquery ajax send.
Ref: https://docs.djangoproject.com/en/1.8/ref/csrf/#ajax
jQuery.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", Cookies.get('csrftoken'));
}
}
});
So, everything is well until I make a ajax call with an beforeSend setting given:
jQuery.ajax({
url: '...',
data: { ... },
beforeSend: function(xhr, settings) {
// This function do shadows the ajaxSetup one.
}
});
So, is there any efficient way to cascade the beforeSend processors on the jQuery.ajaxSetup call?

In fact, in the jQuery document of jQuery Event, setting the beforeSend from the $.ajax call or $.ajaxSetup is called a Local Event, but in the current case, using a $(document).ajaxSend() which is called a Global Event is much more suitable.
Final solution
In the case if you want to add multiple global event processor on ajax send, do not set it on $.ajaxSetup.
Use the ajaxSend event instead!
http://api.jquery.com/ajaxSend/
So the code may look like:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$(document).ajaxSend(function(event, xhr, settings) {
if (!csrfSafeMethod(settings.type) && !settings.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", Cookies.get('csrftoken'));
}
});

If defining a new beforeSend inject in $.ajaxSetup, I can cascade the other ones defined in previous $.ajaxSetup:
(function() {
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
var originBeforeSend = jQuery.ajaxSettings.beforeSend;
jQuery.ajaxSetup({
beforeSend: function(xhr, settings) {
// Call the previous beforeSend processor first.
if(originBeforeSend && originBeforeSend(xhr, settings) === false) {
return false;
}
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", Cookies.get('csrftoken'));
}
}
});
})();
But anyway, if I specified another beforeSend in $.ajax() call, this way has not luck. It was still shadowed.

Related

How do abort parent ajax call in before send method of ajaxsetup

I am using multiple ajax call. But using AjaxSetUp to know whether call is allowed or not , if not then trying to abort this in beforeSendmethod.
here is ajax call
$.ajax({
type : "POST",
url : "/apps/doAction",
xhrFields : "checkIfAllowed",
success : function(response,xhr) {
if(response){
return false;
}
},
error : function(xhr,ajaxOptions,thrownError) {
}
});
And here is AjaxSetUp
$.ajaxSetup({
beforeSend: function(event, xhr, settings) {
event.xhrToAbort=xhr;
if(xhr.xhrFields == "checkIfAllowed"){
$.ajax({
type : "POST",
url : contextpath+ "/apps/auth/isAllowed",
success : function(response,xhr) {
if(response){
// ABORT PARENT CALL ("URL: /apps/doAction") unable to abort parent call..
}
},
error : function(xhr,ajaxOptions,thrownError) {
}
});
}
},
complete: function(event, xhr, settings) {
$('.trans-overlay').hide();
}
});
By replacing event.xhrToAbort=xhr; to event.xhrToAbort=event;
and where you want to abort use like event.xhrToAbort.abort();

Call helper method within Ajax call

I have the following AJAX call:
$.ajaxSetup({
csrfSafeMethod: function(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
},
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
I am getting:
csrfSafeMethod is not defined
Why is csrfSafeMethod not visible from inside beforeSend?
How can I fix this?
Can't you just define a regular function like so:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
Why? Because your method is attached to an object which you don't reference in beforeSend. You can basically imagine it like this:
$.ajaxSetup = function(options) {
var beforeSend = options.beforeSend;
// do stuff...
var xhr = getXHR();
var settings = getSettings();
beforeSend(xhr, settings);
};
$.ajaxSetup({
csrfSafeMethod: function() { ... },
beforeSend: function() {
// `this` is the same as if I called this function in the global scope
// It has no reference to the `options` object
}
});
The actual code in the source code looks like this:
// Allow custom headers/mimetypes and early abort
if ( s.beforeSend &&
( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
// Abort if not done already and return
return jqXHR.abort();
}
Where s is some jQuery object, not in any available scope.
As for how to fix this, you need to declare your function elsewhere or assign your options to a referencable object.
var options = {
csrfSafeMethod: function(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
},
beforeSend: function(xhr, settings) {
if (!options.csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
};
Try this.csrfSafeMethod instead of csrfSafeMethod

Correct way to add request header with jQuery

Sometimes, in IE, my ajax requests do not send the header X-Requested-With. I searched in Google and found 2 ways to do it. Both ways seem to make sense. I want to know if there is any difference between them.
1) Using ajaxSend
$(document).ajaxSend(function (event, request, settings) {
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
});
2) Using AjaxSetup
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
});
If you use the full blown jQuery.ajax() you can use the headers property:
$.ajax({
headers: { "ResponseDataType" : "Json",
"X-Requested-With", "XMLHttpRequest"},
// etc
});
Added DRY version:
(function (window, undefined)
{
function extendedAjax(settings)
{
var defaultSettings = {
headers: { "X-Requested-With": "XMLHttpRequest" }
};
$.extend(defaultSettings, settings);
var jqXHR = $.ajax(settings);
return jqXHR;
}
$.extend({
eajax: extendedAjax
});
})(window);

Extending jQuery ajax success globally

I'm trying to create a global handler that gets called before the ajax success callback. I do a lot of ajax calls with my app, and if it is an error I return a specific structure, so I need to something to run before success runs to check the response data to see if it contains an error code bit like 1/0
Sample response
{"code": "0", "message": "your code is broken"}
or
{"code": "1", "data": "return some data"}
I can't find a way to do this in jQuery out of the box, looked at prefilters, ajaxSetup and other available methods, but they don't quite pull it off, the bets I could come up with is hacking the ajax method itself a little bit:
var oFn = $.ajax;
$.ajax = function(options, a, b, c)
{
if(options.success)
{
var oFn2 = options.success;
options.success = function(response)
{
//check the response code and do some processing
ajaxPostProcess(response);
//if no error run the success function otherwise don't bother
if(response.code > 0) oFn2(response);
}
}
oFn(options, a, b, c);
};
I've been using this for a while and it works fine, but was wondering if there is a better way to do it, or something I missed in the jQuery docs.
You can build your own AJAX handler instead of using the default ajax:
var ns = {};
ns.ajax = function(options,callback){
var defaults = { //set the defaults
success: function(data){ //hijack the success handler
if(check(data)){ //checks
callback(data); //if pass, call the callback
}
}
};
$.extend(options,defaults); //merge passed options to defaults
return $.ajax(options); //send request
}
so your call, instead of $.ajax, you now use;
ns.ajax({options},function(data){
//do whatever you want with the success data
});
This solution transparently adds a custom success handler to every $.ajax() call using the duck punching technique
(function() {
var _oldAjax = $.ajax;
$.ajax = function(options) {
$.extend(options, {
success: function() {
// do your stuff
}
});
return _oldAjax(options);
};
})();
Here's a couple suggestions:
var MADE_UP_JSON_RESPONSE = {
code: 1,
message: 'my company still uses IE6'
};
function ajaxHandler(resp) {
if (resp.code == 0) ajaxSuccess(resp);
if (resp.code == 1) ajaxFail(resp);
}
function ajaxSuccess(data) {
console.log(data);
}
function ajaxFail(data) {
alert('fml...' + data.message);
}
$(function() {
//
// setup with ajaxSuccess() and call ajax as usual
//
$(document).ajaxSuccess(function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
$.post('/echo/json/');
// ----------------------------------------------------
// or
// ----------------------------------------------------
//
// declare the handler right in your ajax call
//
$.post('/echo/json/', function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
});​
Working: http://jsfiddle.net/pF5cb/3/
Here is the most basic example:
$.ajaxSetup({
success: function(data){
//default code here
}
});
Feel free to look up the documentation on $.ajaxSetup()
this is your call to ajax method
function getData(newUrl, newData, callBack) {
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: newUrl,
data: newData,
dataType: "json",
ajaxSuccess: function () { alert('ajaxSuccess'); },
success: function (response) {
callBack(true, response);
if (callBack == null || callBack == undefined) {
callBack(false, null);
}
},
error: function () {
callBack(false, null);
}
});
}
and after that callback success or method success
$(document).ajaxStart(function () {
alert('ajax ajaxStart called');
});
$(document).ajaxSuccess(function () {
alert('ajax gvPerson ajaxSuccess called');
});

javascript frameworks prototype to jquery

I have found the following script which is apparently written using the javascript framework prototype.
Event.observe(window, 'load', function() {
Event.observe( 'btnSubmit', 'click', purchaseCD);
connectToServer();
});
function connectToServer()
{
new Ajax.Updater(
{ success: 'CD Count', failure: 'errors' },
'server_side.php',
{
method: 'get',
onSuccess: function(transport)
{
if (parseInt(transport.responseText)) connectToServer();
}
});
}
function purchaseCD()
{
new Ajax.Updater(
{ success: 'CD Count', failure: 'errors' },
'server_side.php',
{
method: 'get',
parameters: { num: $('txtQty').getValue() }
});
}
Is anyone here able to convert this script to use jQuery instead of prototype? I don't know prorotype at all so I don't understand it.
Ajax.Updater takes, as parameter 1, two containers into which it will update the successful or failed response of a request to the URL given in parameter 2.
What this script does is that upon page load (I translated it below to DOMReady which is not exactly the same, but jQuery convention) an AJAX request is sent to server_side.php. If it gets a response that it understands, it immediately sends off another request, in order to keep the session alive.
This looks like a terrible design. If you're going to do something like that, you definitely want a timeout between the requests.
Another thing that's not very neat with this script is that every AJAX request is handled by the same page - server_side.php - relying on different parameters for instructions on what action to perform. It would appear cleaner to simply request different pages for different actions.
$(function() {
$('#btnSubmit').click(purchaseCD);
connectToServer();
});
function connectToServer() {
$.ajax({
url: "server_side.php",
success: function(res) {
$('#CD Count').html(res);
if(parseInt(res))
connectToServer();
},
error: function(xhr) {
$('#errors').html(xhr.responseText);
}
});
}
function purchaseCD() {
$.ajax({
url: "server_side.php",
success: function(res) {
$('#CD Count').html(res);
},
data: { num: $('#txtQty').val() },
error: function(xhr) {
$('#errors').html(xhr.responseText);
}
});
}

Categories

Resources