Skip to content

Instantly share code, notes, and snippets.

@clarkf
Created February 14, 2012 22:44
Show Gist options
  • Select an option

  • Save clarkf/1831242 to your computer and use it in GitHub Desktop.

Select an option

Save clarkf/1831242 to your computer and use it in GitHub Desktop.
Backbone FormView Helper
/*!
* Backbone BootstrapForm
* Copyright (c) 2012 Clark Fischer <[email protected]>
* V0.0.1
* MIT Licensed
*
* This extension depends on Backbone.FormView.js:
* <https://gist.github.com/1831242#file_backbone.form_view.js>
*/
/*global Backbone, $*/
/*jslint browser: true, indent: 4, sloppy: true */
//BootStrapForm extension of FormView
Backbone.BootstrapForm = Backbone.FormView.extend({
//Show alert -- prepends a div.alert.alert-error to the form
showAlert: function (msg) {
var $form = this.$('form'),
$alert = $form.find('.alert');
if (!$alert.length) {
$alert = $('<div />')
.addClass('alert alert-error')
.css('display', 'none');
$form.prepend($alert);
$alert.slideDown('fast');
}
$alert.html(msg);
},
//markField - Marks the .control-group instead of the actual form element
markField: function ($field, status, message) {
var $e = $field.siblings('.help-inline'),
$group = $field.parents('.control-group');
if (!status) {
if (!$e.length) {
$e = $('<div />')
.addClass('help-inline')
.css('display', 'none');
$field.after($e);
$e.slideDown('fast');
}
$e.html(message);
$group.addClass('error');
} else {
$group.addClass('success');
if ($e.length) {
$e.slideUp('fast', $e.remove);
}
}
},
//unmarkField - Removes the mark
unmarkField: function ($field) {
$field.parents('.control-group').removeClass('error warning success');
}
});
/*!
* Backbone FormView
* Copyright (c) 2012 Clark Fischer <[email protected]>
* V0.0.1
* MIT Licensed
*/
/*global Backbone, $*/
/*jslint browser: true, indent: 4, sloppy: true */
Backbone.FormView = Backbone.View.extend({
//Validation bootstrapper -- This should be called once the form is
//attached to the DOM.
addValidation: function () {
this.$('input').blur(this.validate.bind(this));
this.$('form').submit(this.submit.bind(this));
},
//Mark a field - Mark `$field` as `status` (ie valid or not). Optional
//`message`.
markField: function ($field, status, message) {
var $e = $field.siblings('.message');
if (!status) {
if (!$e.length) {
$e = $('<div />').addClass('message').css('display', 'none');
$field.after($e);
$e.slideDown('fast');
}
$e.html(message);
$field.addClass('error');
} else {
$field.addClass('success');
if ($e.length) {
$e.slideUp('fast', $e.remove);
}
}
},
//Unmark the field - Resets the field to its original state
unmarkField: function ($field) {
$field.removeClass('error warning success');
},
//Show an alert message
showAlert: function (e) {
var $form = this.$('form'),
$a = $form.find('.alert');
if (!$a.length) {
$a = $('<div />')
.addClass('alert')
.css('display', 'false');
$form.prepend($a);
$a.slideDown('fast');
}
$a.html(e);
},
//Validate the form. Does not check for required fields
validate: function () {
var valid = true,
self = this;
this.$('input').each(function () {
var $i = $(this),
id = $i.attr('name'),
val = $i.val(),
v;
self.unmarkField($i);
if (self.validators[id] && val.length) {
v = self.validators[id](val);
self.markField($i, !!v[0], v[1]);
valid = valid && !!v[0];
}
});
return valid;
},
//Check required fields
checkRequired: function () {
var self = this,
valid = true;
$.each(this.required, function (i, rf) {
var $field = self.$('input[name="' + rf + '"]'),
pass = !!$field.val().length;
if (!pass) {
self.markField($field, false, 'Required field');
}
valid = valid && pass;
});
return valid;
},
//Submission handler. Basically, before submission is sent, it validates
//the form and checks for required fields.
submit: function (event) {
event.stopPropagation();
if (this.validate() && this.checkRequired()) {
//Submit
this.performSubmission();
}
return false;
},
//Performs the submission. Turns form into AJAXy form.
performSubmission: function () {
var self = this,
$form = self.$('form');
$.ajax({
type: $form.attr('method'),
url: $form.attr('action'),
data: $.param($form.find('input, select, checkbox, option, radio'))
})
.done(this.submissionSuccess.bind(this))
.fail(this.submissionFailure.bind(this));
},
//Submission success handler -- Please override this
submissionSuccess: function (data) {
throw new Error("Backbone.FormView#submissionSuccess must be " +
" overridden!\nReturned data: " + data);
},
//Submission failure -- Please override this
submissionFailure: function (xhr, status, error) {
throw error;
}
});
//MyForm -- a simple example of a registration form. Make sure we extend
//`Backbone.FormView`. If you use Twitter's awesome Bootstrap, extend the
//`Backbone.BootstrapForm` object.
var myForm = Backbone.FormView.extend({
tagName: 'div',
template: app.templates.myForm,
//Validators
//Validators receive the value of the field and return an array. The first
//element in the array is true/false, indicating whether or not the field
//is valid. The second element is optional, and designates a message to
//be shown next to the field.
//The key of the validation function should map to the `name` attribute of
//the input.
validators: {
username: function (v) {
if (v == 'root') {
//This will mark the field as invalid, and display a message
//next to it.
return [false, "Nice try, buddy"];
}
if (/[^a-z0-9-]/i.test(v)) {
//See above
return [false, "Username must be alphanumeric!"];
}
return [true];
},
//We'll exclude the password field, since we'll accept any kind of
//password
confirm: function (v) {
if (this.$('input#password').val() !== v) {
//The password confirmation does not equal the password!
return [false, "Passwords don't match"];
}
return [true];
},
email: function (v) {
if (/\@aol\.com/i.test(v)) {
return [false, "Get a new email address. It's not 1992 anymore"];
}
return [true];
}
birthYear: function (v) {
if (+v > ((new Date).getFullYear() - 13)) {
return [false, "You must be at least 13 to use this site."]
}
return [true];
}
},
//Required
//Required is simply an array of the `name` attributes of the required
//fields.
required: ['username', 'password', 'confirm', 'email', 'birthYear',
'gender', 'receiveNewsletter', 'hairColor',
'preferredDietBeverage'/*, etc...*/],
submissionSuccess: function (data) {
//`data` now contains whatever the server returned. Do something cool.
this.$('form').slideUp();
this.$el.append("Hey, you signed up. Choose your own adventure!");
showAdventureChoiceDialogue();
},
submissionFailure: function (xhr, status, error) {
this.showAlert("It looks like something went wrong somewhere.<br>" +
"The server sent us some garbage. We'll look into it.");
},
render: function () {
this.$el.html(this.template.render());
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment