Tuesday, October 4, 2011

Backbone.js Validations and jQuery UI

‹prev | My Chain | next›

I got started with Backbone.js validations yesterday. My initial approach was, at best, rudimentary. Fortunately, my co-author on the forthcoming Recipes with Backbone, Nick Gauthier, had some advice on how to improve.

So first up, I drop my basic validation handler in favor of one on the my view. Each appointment in my calendar application is controlled by a Backbone view, so this is where I add my error handling:
        var Appointment = Backbone.View.extend({
          template: _.template($('#calendar-appointment-template').html()),
          initialize: function(options) {
            // ...
            options.model.bind('error', this.handleError, this);
          },
          handleError: function(model, error) {
            if (error.status == 409) {
              alert("This site does not understand CouchDB revisions.");
            }
            else if (typeof(error == 'Array')) {
              alert(error.join("\\n"));
            }
            else {
              alert("This site was made by an idiot.");
            }
          },
        });
The 409 HTTP status check is for errors that might originate from my CouchDB data store. As Nick points out, I should move this into Backbone.sync so that my view does not have to be aware of things like the data store's error messages. I will worry about that another day.

For now, this addition of the check for errors of type 'Array', should account for the errors that I am setting in my model:
      var Models = (function() {
        var Appointment = Backbone.Model.extend({
          // ...
          validate: function(attributes) {
            var errors = [];

            if (!(/\\S/.test(attributes.title)))
              errors.push("Title cannot be blank.");

            if (!/\\S/.test(attributes.description))
              errors.push("Description cannot be blank.");

            if (errors.length > 0)
              return errors;
          },
          // ...
        });
And this does work. When I attempt to edit an existing appointment and remove the required description, I am greeted with:
That is fine and dandy, but I get no error feedback at all when creating appointments. My add-appointment view is a singleton view, primarily because it is using a jQuery UI dialog to present the form:
Nick had suggested binding a view's event listener to the model's error handler, similar to what I am doing with the appointment view:
        var Appointment = Backbone.View.extend({
          template: _.template($('#calendar-appointment-template').html()),
          initialize: function(options) {
            // ...
            options.model.bind('error', this.handleError, this);
          },
          // ...
        });
But I have to confess that I do not know how I would go about doing this with a singleton view. What I do know how to do in a singleton view is add an "error" callback to the create() method:
var AppointmentAdd = new (Backbone.View.extend({
          // ...
          events: {
            'click .ok':  'create'
          },
          create: function() {
            var attributes = {
              title: this.el.find('input.title').val(),
              description: this.el.find('input.description').val(),
              startDate: this.el.find('.startDate').html()
            };

            var options = {
              success: function() { $('#add-dialog').dialog("close"); },
              error: function(model, errors) {
                $('.errors', '#add-dialog').html(errors.join("<br/>")).show();
              }
            };

            appointment_collection.create(attributes, options);
          }
        }));
Now, when I try to create an invalid appointment, I am greeted with:
This gives me a chance to correct my mistake and save successful. Upon successful save, the dialog is hidden from view.

That kinda works. I will call it a night here and see what my co-author (or anyone else) has to say about my solution.

Day #153

No comments:

Post a Comment