Passing Extra Data To JQuery Ajax Callback Functions
Published:
Heads up! This content is more than six months old. Take some time to verify everything still works as expected.
While working with a form that needed ajax handling I ran into an issue. The system I was developing was extremely likely to cause multiple of the same form on the page, one per element. Trying to find and adjust the form post ajax was starting to involve the addition of ids, moving down the dom to move back up, etc. Just nasty, and totally inefficient. So I did a bit of digging to find a way to pass the initial jQuery $form element from the ajax kickoff into the resulting callbacks.
Credit goes to Brad House on stackoverflow for showing me the method. I'm just wrapping it up in a little cleaner syntax and keeping notes for myself. jQuery's callback parameters expect a function pointer. What I'm doing here is simply changing way jQuery goes out to get those functions at run time. By instructing the callbacks to call closure functions with the form, we get all the extra parameters we want access to in the returned function.
This is the relevant part, but I'll add the full working script below for context too.
// ... save: function($form){ jQuery.ajax({ url: viewControls.controller, // Run time call to saveSuccess rather than a static function pointer success: viewControls.events.saveSucccess($form), }); } // ... // Run time closure that returns the required fuction, but includes the $form definition in the function's scope viewControls.events.saveSucccess = function($form){ return function(data) { console.debug('saveSuccess', $form, data); } } // ...
Full code:
viewControls = { controller: "ajax/feedback", /** * Loops over all exposed feedback forms to prepare them */ ready: function () { // Update our path with the proper settings basePath viewControls.controller = settings.basePath + viewControls.controller; // Loop over the forms jQuery(".node-feedback .feedback-controls", context).once( "controls", viewControls.setup ); }, /** * Binds to the form to submit actions via ajax * @param index A numerical value * @param element DOM element * @return null */ setup: function (index, element) { var $form = jQuery(element); // Ensure it can't be submitted with a button interaction $form.submit(function (event) { event.preventDefault(); }); // Wire our controls $form.find("input[type=submit].save").click(viewControls.events.save); $form.find("input[type=submit].send").click(viewControls.events.send); }, /** * Saves the form * @param $form jQuery form element */ save: function ($form) { jQuery.ajax({ url: viewControls.controller, data: $form.serialize() + "&op=save", type: "POST", dataType: "json", success: viewControls.events.saveSucccess($form), error: viewControls.events.saveError($form), complete: viewControls.events.saveComplete($form), }); $form.find("input[type=submit], button").attr("disabled", "disabled"); }, /** * Saves the form changes and sends the feedback along to the end user * @param $form jQuery form element */ send: function ($form) { jQuery.ajax({ url: viewControls.controller, type: "POST", data: $form.serialize() + "&op=send", dataType: "json", success: viewControls.events.sendSucccess($form), error: viewControls.events.sendError($form), complete: viewControls.events.sendComplete($form), }); $form.find("input[type=submit], button").attr("disabled", "disabled"); }, events: { /** * Finds the form and passes it off to be saved * @param event */ save: function (event) { event.preventDefault(); var $form = jQuery(this).parents(".feedback-controls"); viewControls.save($form); }, saveSucccess: function ($form) { return function (data) { console.debug("saveSuccess", $form, data); }; }, saveError: function ($form) { return function (jqXHR, textStatus) { console.debug("saveError", $form); }; }, saveComplete: function ($form) { return function (jqXHR, textStatus) { $form.find("input[type=submit], button").removeAttr("disabled"); }; }, /** * Finds the form and passes it off to be saved * @param event */ send: function (event) { event.preventDefault(); var $form = jQuery(this).parents(".feedback-controls"); viewControls.send($form); }, sendSucccess: function ($form) { return function (data) { console.debug("sendSuccess", $form, data); }; }, sendError: function ($form) { return function (jqXHR, textStatus) { console.debug("sendError", $form); }; }, sendComplete: function ($form) { return function (jqXHR, textStatus) { $form.find("input[type=submit], button").removeAttr("disabled"); }; }, }, }; jQuery(document).ready(viewControls.ready);