jQuery AJAX form submission
Once you’ve got your form validation handled, the question becomes what to do once your form data is valid. Performing an AJAX form submission is reasonably easy, thanks to the jQuery.ajax call:
function signup(form) { jQuery("#alert").remove(); jQuery.ajax({ beforeSend: function() { jQuery.blockUI({ message: '<h1><img src="/static/ajax-loader.gif" /> Working...</h1>' }); }, complete: function() { jQuery.unblockUI(); }, type: "POST", url: "/backend/addnewmember", data: JSON.stringify({"form": form, "session": jQuery.session.get('session')}), dataType: 'json' }).done(function(data) { if (data.result == 'success') { window.location = '/'; } else { jQuery('#maindiv').prepend('<div class="alert alert-warning alert-dismissable" id="alert"><button class="close" type="button" data-dismiss="alert">×</button><strong>' + data.message + '</strong></div>'); jQuery("html, body").animate({ scrollTop: 0 }, "slow"); } }); }
The “beforeSend” and “complete” allow us to provide some progress feedback, in this case, using the jQuery BlockUI plugin to lock the interface and display a popup with a message and an animated “doing something” gif.
“dataType: ‘json'” is crucial, as some browsers will automatically detect the returned data’s type and deserialize it, whilst others won’t, so not setting this or using “datatype” will cause issues in some browsers.
The “data” section allows us to set what data is submitted to the server – if we simply wanted to submit the form, “data: JSON.stringify(form)” would suffice, but if we want to send additional data, or add a “form” object to the JSON rather than having the form be the top-level JSON object, the ‘{“key”: value}’ notation allows us to customize this.
The “.done” section shows how we can check the returned data – in this case, we’re looking for a “result” variable, if the value is “success”, it’ll redirect to the top level of the site, if not, it’ll add a Bootstrap alert to the top of the page with the contents pulled from the “message” variable that was returned, then scroll to the top to ensure the user sees the message.
In this case I’m assuming that the form has been pre-JSONified, for which I use the following custom function, as the built in form.serialize function has some issues with checkbox and radio fields:
function jsonifyform(form){ var json = {}; jQuery.each(jQuery(form).serializeArray(), function() { if (json[this.name]) { if (!json[this.name].push) json[this.name] = [json[this.name]]; json[this.name].push(this.value || ''); } else json[this.name] = this.value || ''; }); return json; }
The Flask backend for the above snippet would be fairly simple:
@main.route('/addnewmember', methods=[ 'POST']) def addnewmember(): formdata = request.get_json(force=True)['form'] session = request.get_json(force=True)['session'] try: # Do some stuff except psycopg2.DatabaseError, e: message = "%s"%e return jsonify({"result":"failure","message": message}) return jsonify(result="success")
We simply need to decode the JSON variables, attempt to do something, if it succeeds, we return a “result” of “success”, and if not, we return a “message” variable with some information – in this case the exception raised by the database. I’ve shown two different methods of using the Flask jsonify helper method here, either is entirely valid, and the top one can be useful when returning a dict from a lower level function to then be JSONified at the top level, like so:
# Lower level function: return {"result":"failure","message": message } # Top level function: returndict = do_something() return jsonify(returndict)