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:
- 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.parseDynamicContent
method 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 AJAX object
$.ajax({
// Normal properties
type: options.type,
url: options.url,
data: options.data,
dataType: dataType,
cache: false,
// Global beforeSend wrapper with user defined function
beforeSend: function () {
// Execute user defined method
if (typeof options.beforeSend === 'function') {
options.beforeSend();
}
},
// Global success wrapper which will redirect if url specified is a json object
// with the RedirectUrl tag
success: function (data) {
var jData;
var redirected = false;
try {
if (data) {
jData = $.parseJSON(data);
if (jData && (typeof jData.RedirectUrl !== 'undefined' && jData != null && jData.RedirectUrl.length > 0)) {
var performRedirect = true;
if (typeof options.beforeRedirect !== 'undefined') {
// beforeRedirect returns true if the redirect is still to occur otherwise false
performRedirect = options.beforeRedirect(jData);
}
if (performRedirect) {
redirected = true;
// Using replace based off SO - http://stackoverflow.com/questions/503093/how-can-i-make-a-redirect-page-in-jquery-javascript
window.location.replace(jData.RedirectUrl);
}
}
}
} catch (e) {
// not json
}
// Execute user defined method
if (!redirected) {
if ((options.success && typeof options.success === 'function')) {
options.success(data);
}
// always done after the success to ensure any dyanamic elements have been loaded
if (typeof options.dynamicValidation != 'undefined') {
$.validator.unobtrusive.parseDynamicContent(options.dynamicValidation);
}
}
},
error: function (xhr, status, err) {
if (typeof options.error === 'function') {
options.error(xhr, status, err);
}
if (xhr.status == 400) {
alert(err);
}
}
});
};
Example of usage is (Methods such as addUploadTableSpinner just included for examples):
$.ajaxWithRedirect({
beforeSend: addUploadTableSpinner(),
type: "POST",
url: '/MyUrl/Delete' + '?sessionId=' + sessionId,
dataType: "html",
beforeRedirect: function (data) {
closePopup();
// show the user success message
showDeleteSuccessfulPopup(data.RedirectUrl);
showSuccessfulPopup = false;
// don't do the redirect
return false;
},
success: function (data) {
if (data.length == 0) {
deleteRow.remove();
} else if (showSuccessfulPopup) {
deleteRow.html(data);
closePopup();
showDeleteSuccessfulPopup();
}
removeUploadTableSpinner();
}
});