Using Backbone to improve multiselects

Sometimes you need to ask a users for multiple answers to a single question. But what's the best way to go about it?

Checkbox-field

A multiselect input field is kind of strange for the user, sticks out and doesn't really behave like everything else on the web.

A bunch of checkboxes is better for the user ... but have you ever tried handling a form with dynamically created checkboxes? Let alone creating useful tests and consolidating everything into a single list of values. No decent forms framework will let you do that easily.

I had to solve this similar problem for a time and attendance software I worked on, so I made a Javascript thing to convert a select field into a checkbox-field. Then I made it into a simple jquery plugin thing for everyone to use :)

Check out the demo!

The idea is pretty simple:

What I really love about the Backbone approach is that all of this works almost magically. Instead of bending over backwards to get checkboxes and the hidden multiselect synced up, all I had to do was create some models, some views and tell them how they are connected.

This is how the field itself is created

$multiselect.find("option").each(function (i, el) {
  var $el = $(el);
  // hidden behind the scenes here is that:
  // 1. creating a Checkbox, correctly binds together all needed events
  // 2. adding it to checkboxes, takes care of rendering and adding to the DOM
  checkboxes.add(
    new Checkbox({
      value: $el.val(),
      label: $el.html(),
      selected: $el.attr("selected"),
    })
  );
});

And to make sure data is synced up between its three representations (multiselect, visual checkboxes, the data structure itself), all it takes is this:

var Checkbox = Backbone.Model.extend({
  initialize: function () {
    this.bind("change:selected", this.toggled);

    this.attributes.id = this.cid;
  },

  toggled: function () {
    var $opt = $multiselect.find("option[value=" + this.get("value") + "]");

    if (this.get("selected")) {
      $opt.attr("selected", "1");
    } else {
      $opt.removeAttr("selected");
    }
  },
});

Yep, that's the whole model and that's all it takes to sync everything up. Pretty cool huh? I remember trying to do this with just jQuery once ... I nearly stabbed my eyes out to end the misery.

All in all the whole thing is just 123 sloc, which can only mean one thing: Backbone is cool.

If you use my checkbox-field library, it's only going to be a single sloc for you:

$("#my_selector").checkboxField();

That's it :)

Let me know what you think.