AJAX with jQuery

jQuery is a small JavaScript library commonly used to simplify workingwith the DOM and JavaScript in general. It is the perfect tool to makeweb applications more dynamic by exchanging JSON between server andclient.

JSON itself is a very lightweight transport format, very similar to howPython primitives (numbers, strings, dicts and lists) look like which iswidely supported and very easy to parse. It became popular a few yearsago and quickly replaced XML as transport format in web applications.

Loading jQuery

In order to use jQuery, you have to download it first and place it in thestatic folder of your application and then ensure it’s loaded. Ideallyyou have a layout template that is used for all pages where you just haveto add a script statement to the bottom of your <body> to load jQuery:

  1. <script type=text/javascript src="{{
  2. url_for('static', filename='jquery.js') }}"></script>

Another method is using Google’s AJAX Libraries API to load jQuery:

  1. <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  2. <script>window.jQuery || document.write('<script src="{{
  3. url_for('static', filename='jquery.js') }}">\x3C/script>')</script>

In this case you have to put jQuery into your static folder as a fallback, but it willfirst try to load it directly from Google. This has the advantage that yourwebsite will probably load faster for users if they went to at least oneother website before using the same jQuery version from Google because itwill already be in the browser cache.

Where is My Site?

Do you know where your application is? If you are developing the answeris quite simple: it’s on localhost port something and directly on the rootof that server. But what if you later decide to move your application toa different location? For example to http://example.com/myapp? Onthe server side this never was a problem because we were using the handyurl_for() function that could answer that question forus, but if we are using jQuery we should not hardcode the path tothe application but make that dynamic, so how can we do that?

A simple method would be to add a script tag to our page that sets aglobal variable to the prefix to the root of the application. Somethinglike this:

  1. <script type=text/javascript>
  2. $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
  3. </script>

The |safe is necessary in Flask before 0.10 so that Jinja does notescape the JSON encoded string with HTML rules. Usually this would benecessary, but we are inside a script block here where different rulesapply.

Information for Pros

In HTML the script tag is declared CDATA which means that entitieswill not be parsed. Everything until </script> is handled as script.This also means that there must never be any </ between the scripttags. |tojson is kind enough to do the right thing here andescape slashes for you ({{ "</script>"|tojson|safe }} is rendered as"<\/script>").

In Flask 0.10 it goes a step further and escapes all HTML tags withunicode escapes. This makes it possible for Flask to automaticallymark the result as HTML safe.

JSON View Functions

Now let’s create a server side function that accepts two URL arguments ofnumbers which should be added together and then sent back to theapplication in a JSON object. This is a really ridiculous example and issomething you usually would do on the client side alone, but a simpleexample that shows how you would use jQuery and Flask nonetheless:

  1. from flask import Flask, jsonify, render_template, request
  2. app = Flask(__name__)
  3.  
  4. @app.route('/_add_numbers')
  5. def add_numbers():
  6. a = request.args.get('a', 0, type=int)
  7. b = request.args.get('b', 0, type=int)
  8. return jsonify(result=a + b)
  9.  
  10. @app.route('/')
  11. def index():
  12. return render_template('index.html')

As you can see I also added an index method here that renders atemplate. This template will load jQuery as above and have a little form wherewe can add two numbers and a link to trigger the function on the serverside.

Note that we are using the get() method herewhich will never fail. If the key is missing a default value (here 0)is returned. Furthermore it can convert values to a specific type (likein our case int). This is especially handy for code that istriggered by a script (APIs, JavaScript etc.) because you don’t needspecial error reporting in that case.

The HTML

Your index.html template either has to extend a layout.html template withjQuery loaded and the $SCRIPT_ROOT variable set, or do that on the top.Here’s the HTML code needed for our little application (index.html).Notice that we also drop the script directly into the HTML here. It isusually a better idea to have that in a separate script file:

  1. <script type=text/javascript>
  2. $(function() {
  3. $('a#calculate').bind('click', function() {
  4. $.getJSON($SCRIPT_ROOT + '/_add_numbers', {
  5. a: $('input[name="a"]').val(),
  6. b: $('input[name="b"]').val()
  7. }, function(data) {
  8. $("#result").text(data.result);
  9. });
  10. return false;
  11. });
  12. });
  13. </script>
  14. <h1>jQuery Example</h1>
  15. <p><input type=text size=5 name=a> +
  16. <input type=text size=5 name=b> =
  17. <span id=result>?</span>
  18. <p><a href=# id=calculate>calculate server side</a>

I won’t go into detail here about how jQuery works, just a very quickexplanation of the little bit of code above:

  • $(function() { … }) specifies code that should run once thebrowser is done loading the basic parts of the page.

  • $('selector') selects an element and lets you operate on it.

  • element.bind('event', func) specifies a function that should runwhen the user clicked on the element. If that function returnsfalse, the default behavior will not kick in (in this case, navigateto the # URL).

  • $.getJSON(url, data, func) sends a GET request to url and willsend the contents of the data object as query parameters. Once thedata arrived, it will call the given function with the return value asargument. Note that we can use the $SCRIPT_ROOT variable here thatwe set earlier.

Check out the example source for a fullapplication demonstrating the code on this page, as well as the samething using XMLHttpRequest and fetch.