Tag Archives: jquery

Glow Javascript library

Only just come across the Glow Javascript library that the BBC released under the Apache license a couple of months ago. It looks good, and has excellent API documentation as well as discussions of general usage for the majority of the tools.

In particular it has widgets for auto-complete text inputs, a simple class for validating form input and supports CSS-style selectors for referencing DOM objects.

Being that the BBC is mightily concerned with scheduled transmissions, Glow has an implementation of a timetable for displaying concurrent “tracks” of time data – I think this would complement the Simile timeline library in various situations.

Seeing as I can’t do Javascript without jQuery or getting depressed, Glow is very interesting.

Ignore the docs, use ‘value’ to set value in jQuery.UI.progressbar

The online documentation for the progressbar plugin for jQuery.UI says to use “progress” as the keyword when setting the value of your progress bar, something like this:

var percent = Math.floor(data.received / data.size * 100);
$("#upload-progress").progressbar('progress', percent);

It doesn’t work. At least, it doesn’t work with the 1.6rc5 release. The correct keyword for setting the value is “value”:

var percent = Math.floor(data.received / data.size * 100);
$("#upload-progress").progressbar('value', percent);

The documentation doesn’t mention the default range of values for progressbar, but it is from 0 to 100. Actually the docs have all this stuff about showing custom text and the numeric value in the bar and that doesn’t seem to work neither.

In a way this small imperfection makes me admire jQuery even more. And this post is a kiss on her cheek.

I’ve filed a bug! #3871 on jQuery.UI’s Trac.

Encoding lists in Django for jQuery

Several times I have needed to implement a form for a Django model where one field’s value determines the available choices for a second field. Recently I finished a project where the user had to choose from a list of departments in our office, and then choose from a list of staff working for the chosen department.

The Django model looks like this:

EMPLOYEES = (
    ('Finance', 'Adam'),
    ('Finance', 'Clare'),
    ('Finance', 'Dave'),
    ('Housekeeping', 'Frank'),
    ('Housekeeping', 'Nat'),
    ('Marketing', 'Nigel'),
    ('Marketing', 'Valerie'),
)

def department_choices():
    depts = list(set(d for d, e in EMPLOYEES))
    depts.sort()
    for d in depts:
        yield (d, d)

def employee_choices():
    for d, e in EMPLOYEES:
        yield (e, e)

class EmployeeOfTheYear(models.Model):
    department = models.CharField(max_length=250, choices=department_choices())
    employee = models.CharField(max_length=250, choices=employee_choices())

In this application the site visitor will be creating EmployeeOfTheYear objects, and the new object form should display department and employee fields as lists of pre-defined department names and pre-defined employee names.

So then wickles! A quick Django view and template for making a new object creates markup with SELECT inputs for department and employee fields with the OPTION elements restricted to just those departments and employees defined by the evil management types on the 100th floor. The markup will be similar to this:

<select name="id_department">
    <option value="Finance">Finance</option>
    ...
</select>

<select name="id_employee">
    <option value="Adam">Adam</option>
    ...
</select>

(If your corporate culture lacks a 100th floor you might imagine a variation where departments and employees are defined in your corporate directory, and where you have mad skillz sufficient to create lists of the departments and employees using LDAP and Python.)

The problem is that choosing a department from the department SELECT menu has no bearing on the choices available in the employee SELECT menu. It jolly well ought to.

I use jQuery for nearly every piece of JavaScript functionality in my projects. jQuery makes so many tedious tasks a matter of a few lines, I wish I could reclaim the hours spent debugging my scripts before I discovered this magical library.

With jQuery and the texotela plugin for select boxes we can create an event handler that fires whenever the visitor makes a choice from the department menu so that the choices in the employee menu are restricted to just the employees matching the chosen department. This is known as a cascading select input or two-level select input.

The script to do this does the following:

  • Take the chosen value for the department
  • Remove all options for the employee SELECT input element
  • Query the server via AJAX for a list of employees in the chosen department
  • Insert the results as options for the employee SELECT element

Here is the JavaScript to do all that, using jQuery’s excellent selector syntax to install the handler for the form’s id_department SELECT element:

employee_url = '/find_employees/'

$(document).ready(function() {
    $("#id_department").change(function() {
        var dept = $(this).selectedValues();
        $("#id_employee").removeOption(/./);
        $("#id_employee").ajaxAddOption(employee_url, {dept: dept}, false);
    });
});

There are implementation details hard-coded in there.

  1. The URL for retrieving a list of employees is /find_employees/
  2. The /find_employees/ URL is queried with the chosen department passed in as the dept query variable
  3. The Django form inputs must be named id_department and id_employee

When a visitor chooses ‘Housekeeping’ from the department SELECT the event handler will GET /find_employees/?dept=Housekeeping and will expect a JSON-encoded list of options for insertion in the employees menu. The texotela plugin says the format for the employee list has to be like so:

{
    "option_value_1": "option_text_1",
    "option_value_2": "option_text_2"
}

(At which point I wonder if my mistrust of JavaScript is misplaced. That damn JSON-encoded data just is a Python dictionary! But no, a Python dictionary is unordered, whereas those conniving JavaScript curly-braces denote object properties. And the absence of a final comma on the last value/option pair can make all the debugging difference in the world. Not the same thing at all.)

And finally the view itself. This view must return a JSON-encoded dictionary of employee names that match the department given by the ‘dept’ query parameter. However a regular Python dictionary is no good because the order of items is significant: the choices in the employee SELECT should be listed alphabetically. We can use Django’s SortedDict, a sub-class of dict that maintains key order.

from django.http import HttpResponse

def find_employees(request):
    """Return a JSON list matching search term."""
    from django.utils.datastructures import SortedDict
    from django.utils import simplejson
    from models import EMPLOYEES

    dept = request.GET.get('dept', '').lower()

    if dept:
        employees = [e for d, e in EMPLOYEES if dept == d.lower()]
    else:
        employees = [e for d, e in EMPLOYEES]
    employees.sort()

    d = SortedDict([(e, e) for e in employees])
    return HttpResponse(simplejson.dumps(d, ensure_ascii=False), mimetype='application/json')

I need a matching rule in urls.py to direct requests to the JSON view:

urlpatterns = patterns('myproject.myapp.views',
    url(r'^find_employees/$', 'find_employees', name="find_employees"),
)

Things I like about this approach:

  • The form works perfectly without JavaScript
  • If the submitted form doesn’t validate, the visitor’s department and employee choices are still selected when the form is redisplayed
  • The JavaScript is clear and concise

In the real application the EMPLOYEES and DEPARTMENTS are lists of objects wrapping LDAP results, but I hope this explanation is clear enough to show how the it all hangs together to help the visitor use what would otherwise be an unhelpful couple of SELECT inputs.