Binding A Backbone View To A Model, To Enable and Disable A Button


Continuing the contrived example from yesterday – a very simple login form – I wanted to show how Joey and I are using backbone’s events and models to enable and disable a button on the form.

The Form Layout And Functionality

It’s a very simple form. It has a username and password text box, and a button. What I want to to is make the button disabled initially, and then enable it when a username and password have been supplied.

Here’s the form HTML and layout:

Screen shot 2011 06 15 at 1 13 39 PM

The Credentials Model

We need something on the credentials model for the view to pay attention to, to know when to enable and disable the button. A “validated” event would be a great way to listen to the model’s changes for this purpose. Then, if the model is valid we can enable the button and if the model is invalid, we can disable the button.

In this code, we are setting up a “changed” even listener in the model’s initializer. The “changed” even fired any time an attribute on the model is being changed. For example, calling “model.set({something: “whatever”})” will change the model’s “something” attribute and cause the change event to fire. Within our change even handler, we are checking to see if the model has both a username and a password. If both are present, the model is valid. If one or both are missing, the model is not valid. We are then raising (triggering) the “validated” event and passing along the knowledge of whether or not the model is valid.

The Login View

I’ve updated this a little from yesterday’s example and I’m using backbone’s built in event system instead JQuery’s for binding the username and password inputs. I’ve also added few lines to the initializer to bind to the model’s “validated” event and store the view on the model.

Line 15 binds the view’s validated method to the model’s validated event. This gives us a way to have the view pay attention to the model so that we can change the login button’s disabled attribute. Line 14 is also assigning the view to the model’s .view attribute so that we can access the view in the validated event handler.

The validated function receives the valid argument to tell us whether or not the model is valid. If it is valid, we remove the “disabled” attribute. If it’s not valid, we add the “disabled” attribute.

Notice that the validated function is calling this.view.loginbutton to get to the login button. I’m doing this because “this” in the context of the event handler method is the object that raised the event. In this case, the object that raised the event is the model. I need the loginButton attribute from the view, though, so I have attached the view to the model in line 14 which makes “this.view” available in the validated method.

Honestly, this part confused me. I thought the context of “this” in the validated method was going to be the view itself, not the model. Can anyone explain why it’s the model and not the view?

Putting It All Together

Now that our model has a validated event and our view is binding to it, we can enter a username and password to enable the login button:

Screen shot 2011 06 15 at 2 02 32 PM

and when we click on the login button, we get a pop up message telling us the username and password:

Screen shot 2011 06 15 at 2 03 24 PM

If you’re interested in seeing all of the code for this example, head over to the gist and grab the last 2 files. One is a javascript file and the other is the html file, with all of this running.

A Small Problem: Blur vs Change

There is a small problem with this example, though. You have to cause the username and password fields to lose focus before the changed events will fire and populate the model with the data. So, as you are typing into the password box (after setting a username), the login button is still disabled. Once you tab or click out of the password box, the button enables.

I thought the change even was supposed to fire for every keystroke that happened in an input box, while the blue event only fired on blur of the input. Can anyone clarify this for me or tell me what I’m doing wrong / how to fix it?

Is There A Better Way With Backbone?

I have this sneaking suspicion that there’s a better, more declarative way to bind the view and model together, leading to less code than my example shows. If anyone knows how to get this done in a better way, please share!

Still A Contrived Example

One of the commenters on my previous post was asking why you would want to use backbone over JQuery for such simple functionality. In truth, I probably wouldn’t use backbone for such a small piece of functionality in a production application. You could accomplish the same thing with JQuery alone, in much less code. I realize that the examples I’m giving are contrived and not very real-world. They are just examples, though, and would hopefully spark a little more interest or help someone else find that “AHA!” moment on when, where and why they would want to use something like Backbone.

Intro To Backbone.js: How A Winforms Developer is At Home In Javascript