patternjavascriptMinor
Wrapper for jquery ajax to ensure redirects occur on clientside
Viewed 0 times
ajaxoccurensurewrapperjqueryforredirectsclientside
Problem
Recently I had the need to make some ajax calls within a MVC 3.0 with Razor and jQuery application. After a bit of trial and error and refactoring it was discovered that a number of different needs were required. These included:
With these in place we did a bit of serverside code that ensured we hijacked the
Some notes:
I'm definitely pretty raw in the Javascript department so any comments or improvements on the code below would be greatly appreciated.
```
$.ajaxWithRedirect = function (options) {
// If dataType wasn't specified in the options, default to 'html'
var dataType = (options.dataType !== undefined) ? options.dataType : 'html';
// jQuery
- The serverside code would be responsible for creating any redirect urls and we wanted to stick with the inherited controller RedirectToAction() method where possible in our controller actions.
- We are using jQuery unobtrusive validation and some situations meant that new forms were rendered onto the view via ajax. That meant we needed to ensure those new form fields contained and validated when required.
- We wanted the flexibility to return html (PartialViews), json or tell the client side it was a redirect and the URL to redirect to (initiated via 1 above).
- Before page redirects at times we wanted to show div popups such as a Success confirmation. Hence although we were using RedirectToAction() in the backend we wanted the javascript to actually perform the redirect.
With these in place we did a bit of serverside code that ensured we hijacked the
RedirectToAction() result and returned a json object instead. I'm fairly happy that code works. What I'm not sure about is the javascript code that I use to perform the result. Some notes:
- The
$.validator.unobtrusive.parseDynamicContentmethod will ensure the new html elements are rebound for validation. I did not write that code so have not added it for review.
- For options 1, 2 and 3 above we didn't want the person writing the ajax to always have to worry about these so esentially wanted them to just be handled so to speak.
I'm definitely pretty raw in the Javascript department so any comments or improvements on the code below would be greatly appreciated.
```
$.ajaxWithRedirect = function (options) {
// If dataType wasn't specified in the options, default to 'html'
var dataType = (options.dataType !== undefined) ? options.dataType : 'html';
// jQuery
Solution
It seems to me that you're duplicating some of what
Here's a version that focusses solely on the redirection (i.e. it doesn't worry about the data type, the validation stuff, or doing its own error handling). It's just a transparent layer on top of the normal
The code's below, and here's a demo
Point is that you should be able use
$.ajax() will do for you (such as calling beforeSend) and you're also leaving the door open for using the deferred promise methods (then, done, fail, etc.) that jQuery's XHR object provides.Here's a version that focusses solely on the redirection (i.e. it doesn't worry about the data type, the validation stuff, or doing its own error handling). It's just a transparent layer on top of the normal
$.ajax() function.The code's below, and here's a demo
$.ajaxWithRedirect = function (options) {
"use strict";
var deferred = $.Deferred(),
successHandler,
xhr;
// force no-cache
options.cache = false;
// get a copy of the success handler...
successHandler = options.success;
// ... and replace it with this one
options.success = function (data) {
var contentType = xhr.getResponseHeader("Content-Type"),
performRedirect = true,
redirectUrl = null,
args = [].slice.call(arguments, 0),
json;
// If response isn't there or isn't json,
// skip all the redirect logic
if( data && (/json/i).test(contentType) ) {
// If json was requested, and json received, jQuery will
// have parsed it already. Otherwise, we'll have to do it
if( options.dataType === 'json' ) {
redirectUrl = data.RedirectUrl;
} else {
try {
json = $.parseJSON(data);
redirectUrl = json.RedirectUrl;
} catch(e) {
// no-op
}
}
// check the redirect url
if( redirectUrl && typeof redirectUrl === 'string') {
// Is there a beforeRedirect handler?
if( typeof options.beforeRedirect === 'function' ) {
// pass all the arguments to the beforeRedirect handler
performRedirect = options.beforeRedirect.apply(null, args);
}
// unless strictly false, go ahead with the redirect
if( performRedirect !== false ) {
location.replace(redirectUrl);
// and stop here. No success and/or deferred handlers
// will be called since we're redirecting anyway
return;
}
}
}
// no redirect; forward everything to the success handler(s)
if( typeof successHandler === 'function' ) {
successHandler.apply(null, args);
deferred.resolve.apply(null, args);
}
};
// Make the request
xhr = $.ajax(options);
// Forward the deferred promise method(s)
xhr.fail(deferred.reject);
xhr.progress(deferred.notify);
// Replace the ones already on the xhr obj
deferred.promise(xhr);
return xhr;
};Point is that you should be able use
$.ajaxWithRedirect exactly like you'd use vanilla $.ajax, including all the shiny deferred promise stuff. The only thing it does different from the normal version is set options.cache = false, and that it has a beforeRedirect callback.Code Snippets
$.ajaxWithRedirect = function (options) {
"use strict";
var deferred = $.Deferred(),
successHandler,
xhr;
// force no-cache
options.cache = false;
// get a copy of the success handler...
successHandler = options.success;
// ... and replace it with this one
options.success = function (data) {
var contentType = xhr.getResponseHeader("Content-Type"),
performRedirect = true,
redirectUrl = null,
args = [].slice.call(arguments, 0),
json;
// If response isn't there or isn't json,
// skip all the redirect logic
if( data && (/json/i).test(contentType) ) {
// If json was requested, and json received, jQuery will
// have parsed it already. Otherwise, we'll have to do it
if( options.dataType === 'json' ) {
redirectUrl = data.RedirectUrl;
} else {
try {
json = $.parseJSON(data);
redirectUrl = json.RedirectUrl;
} catch(e) {
// no-op
}
}
// check the redirect url
if( redirectUrl && typeof redirectUrl === 'string') {
// Is there a beforeRedirect handler?
if( typeof options.beforeRedirect === 'function' ) {
// pass all the arguments to the beforeRedirect handler
performRedirect = options.beforeRedirect.apply(null, args);
}
// unless strictly false, go ahead with the redirect
if( performRedirect !== false ) {
location.replace(redirectUrl);
// and stop here. No success and/or deferred handlers
// will be called since we're redirecting anyway
return;
}
}
}
// no redirect; forward everything to the success handler(s)
if( typeof successHandler === 'function' ) {
successHandler.apply(null, args);
deferred.resolve.apply(null, args);
}
};
// Make the request
xhr = $.ajax(options);
// Forward the deferred promise method(s)
xhr.fail(deferred.reject);
xhr.progress(deferred.notify);
// Replace the ones already on the xhr obj
deferred.promise(xhr);
return xhr;
};Context
StackExchange Code Review Q#17830, answer score: 4
Revisions (0)
No revisions yet.