Awesome Model Binding For Backbone.js
A few weeks ago, Brandon Satrom introduced me to Knockout.js by pointing me to a video by Steve Sanderson. I haven’t had a chance to try KO, yet, but I have to say I was blown away by the data-binding capabilties. Then, Brandon puts up this blog post and talks about how he made KO even more awesome by eliminating the data-* attributes that KO needs, from his HTML markup.
Needless to say, I was envious. KO’s data binding is impressive – especially compared to what we get out of the box with Backbone. Then this last week, Neive pointed me to a post by Brad Phelan that talks about adding better model binding to Backbone.
With all of this gong on, I was inspired! So I set out to build not just a manual configuration model binder, but a convention based binder that I can use in my apps to reduce the amount of view logic and code I need.
Introducing Backbone.ModelBinding
I wanted to get rid of code that binds my model’s change events to the form input, and form input change event to the model attribute. And after a handful of hours hacking away, this weekend, I produced a Backbone plugin that does what I want.
Backbone.ModelBinding: Awesome Model Binding For Backbone.js
Head over to the link to check out the detail on how to get started, what prerequisites you’ll need, etc.
An Example
In one of my previous posts, I talked about a form that uses backbone to manage the add/edit process for patient medications. Since I already had this code in my head and there was a fair amount of backbone view code to manage all of the model binding between the form elements and model, I decided that this would be the first place I use my new plugin – this is what drove out the initial requirements and implementation.
Here is the screen shot from the previous post, showing a list of medications with an add/edit form above that.
There are 7 input fields and one select box on this form. To code to bind these fields to my model previously looked like this:
Given the number of inputs on this form, this code isn’t too bad. I was able to use some javascript and jQuery magic to reduce the amount of code I needed for each of the input boxes. However, I ended up with code to handle input fields and select fields, separately.
Now let’s look at this code with Backbone.ModelBinding in place.
Notice a small difference in the amount of code needed to bind all 8 of those fields (7 inputs, 1 select)? What this comparison doesn’t show is the code that would have been needed to bind a model change back out to the form’s input fields. The one line of code in the render function, though, to call the Backbone.ModelBinding plugin handles this as well.
Now I can not only get my form bound to my models with a simple convention, but I can also have any other code on the page update my model and if the model happens to be bound to the form, the form will be updated as well.
A Simiple Convention, With Unconventional Support
The Backbone.ModelBinding convention to make this work is very simple. The #id of the html form element is used as the model’s attribute and vice-versa. For example, in the above screen shot my “Trade name” field has an id of #trade_name. The model, then, has an attribute called trade_name.
If you don’t have your fields and model attributes aligned to this convention, though, Backbone.ModelBinding still supports you! But you have to drop back to manual configuration of the binding.
Still, this is pretty simple. All you need to do is specify which form element is being bound to which model attribute and Backbone.ModelBinding takes care of the rest for you. The only requirement is that the html element you specify must fire a ‘change’ event that jQuery can bind to, and must be able to have it’s value set via jQuery’s ‘.val’ method.
What Are You Waiting For?
Well? What are you waiting for? Go grab a copy of Backbone.ModelBinding and try it out! It’s still verfdy early in it’s development, so it only supports input and select elements, right now. But! It’s open source – MIT License – and hosted on Github. If it doesn’t do what you need or does something you don’t want it to do, I’m always open to receiving pull requests.