Coder Social home page Coder Social logo

backbone-forms's Introduction

backbone-forms

A flexible, customisable form framework for Backbone.js applications.

  • Simple schema definition to auto-generate forms
  • Validation
  • Nested forms
  • Advanced and custom editors (e.g. NestedModel, List, Date, DateTime)
  • Custom HTML templates

Example: Quickly generate forms to edit models

var User = Backbone.Model.extend({
    schema: {
        title:      { type: 'Select', options: ['Mr', 'Mrs', 'Ms'] },
        name:       'Text',
        email:      { validators: ['required', 'email'] },
        birthday:   'Date',
        password:   'Password',
        address:    { type: 'NestedModel', model: Address },
        notes:      { type: 'List', itemType: 'Text' }
    }
});

var user = new User();

var form = new Backbone.Form({
    model: user
}).render();

$('body').append(form.el);

Example: Fully customise forms and templates

HTML:

<script id="formTemplate" type="text/html">
    <form>
        <h1>New User</h1>

        <h2>Main Info</h2>
        <div data-fields="title,name,birthday"></div>

        <h2>Account Info</h2>
        <h3>Email</h3>
        <div data-fields="email"></div>

        <h3>Password</h3>
        <p>Must be at least 8 characters long</p>
        <div data-editors="password"></div>
    </form>
</script>

JavaScript:

var UserForm = Backbone.Form.extend({
    template: _.template($('#formTemplate').html()),

    schema: {
        title:      { type: 'Select', options: ['Mr', 'Mrs', 'Ms'] },
        name:       'Text',
        email:      { validators: ['required', 'email'] },
        password:   'Password'
    }
});

var form = new UserForm({
    model: new User()
}).render();

$('body').append(form.el);

Live editable demos

Table of Contents:

Dependencies:

Include backbone-forms.js:

<script src="backbone-forms/distribution/backbone-forms.min.js"></script>

Optionally, you can include the extra editors, for example the List editor:

<script src="backbone-forms/distribution/editors/list.min.js"></script>

To use a custom template pack, e.g. Bootstrap, include the relevant files after backbone-forms.js.

<script src="backbone-forms/distribution/templates/bootstrap.js"></script>
<link href="backbone-forms/distribution/templates/bootstrap.css" rel="stylesheet" />

If you use Backbone with browserify or node.js, you can just require('backbone-forms'); in your index file. If doing this you will need to set Backbone.$, e.g. Backbone.$ = require('jquery').

Note there is also a distribution file for RequireJS / AMD.

Back to top

Forms are generated from a schema, which can be defined on the form itself or on a model.

The schema keys should match the attributes that get set on the model. type defaults to Text. When you don't need to specify any options you can use the shorthand by passing the editor name as a string. See schema definition for more information.

var User = Backbone.Model.extend({
    schema: {
        title:      { type: 'Select', options: ['Mr', 'Mrs', 'Ms'] },
        name:       'Text',
        email:      { validators: ['required', 'email'] },
        birthday:   'Date',
        password:   'Password',
        address:    { type: 'NestedModel', model: Address },
        notes:      { type: 'List', itemType: 'Text' }
    }
});

var user = new User();

var form = new Backbone.Form({
    model: user
}).render();

$('body').append(form.el);

Once the user is done with the form, call form.commit() to apply the updated values to the model. If there are validation errors they will be returned. See validation for more information.

var errors = form.commit(); // runs schema validation

or

var errors = form.commit({ validate: true }); // runs schema and model validation

To update a field after the form has been rendered, use form.setValue:

model.on('change:name', function(model, name) {
    form.setValue({ name: name });
});

Usage without models

You can create a form without tying it to a model. For example, to create a form for a simple object of data:

var form = new Backbone.Form({
    //Schema
    schema: {
        id:         'Number',
        name:       'Text',
        password:   'Password'
    },

    //Data to populate the form with
    data: {
      id: 123,
      name: 'Rod Kimble',
      password: 'cool beans'
    }
}).render();

Then instead of form.commit(), do:

var data = form.getValue(); //Returns object with new form values

Initial data

If a form has a model attached to it, the initial values are taken from the model's defaults. Otherwise, you may pass default values using the schema.data.

Back to top

Options

  • model

    The model to tie the form to. Calling form.commit() will update the model with new values.

  • data

    If not using the model option, pass a native object through the data option. Then use form.getValue() to get the new values.

  • schema

    The schema to use to create the form. Pass it in if you don't want to store the schema on the model, or to override the model schema.

  • fieldsets

    An array of fieldsets descriptions. A fieldset is either a list of field names, or an object with legend and fields attributes. The legend will be inserted at the top of the fieldset inside a <legend> tag; the list of fields will be treated as fields is below. fieldsets takes priority over fields.

  • fields

    An array of field names (keys). Only the fields defined here will be added to the form. You can also use this to re-order the fields.

  • submitButton {String}

    If provided, creates a submit button at the bottom of the form using the provided text.

  • idPrefix

    A string that will be prefixed to the form DOM element IDs. Useful if you will have multiple forms on the same page. E.g. idPrefix: 'user-' will result in IDs like 'user-name', 'user-email', etc.

    If not defined, the model's CID will be used as a prefix to avoid conflicts when there are multiple instances of the form on the page. To override this behaviour, pass a null value to idPrefix.

  • template

    The compiled template to use for generating the form.

Events

Backbone.Form fires the following events:

  • change

    This event is triggered whenever something happens that affects the result of form.getValue().

  • focus

    This event is triggered whenever this form gains focus, i.e. when the input of an editor within this form becomes the document.activeElement.

  • blur

    This event is triggered whenever this form loses focus, i.e. when the input of an editor within this form stops being the document.activeElement.

  • <key>:<event>

    Events fired by editors within this form will bubble up and be fired as <key>:<event>.

    form.on('title:change', function(form, titleEditor, extra) {
        console.log('Title changed to "' + titleEditor.getValue() + '".');
        // where extra is an array of extra arguments that
        // a custom editor might need
    });
  • submit

    Fired when the form is submitted. The native Event is passed as an argument, so you can do event.preventDefault() to stop the form from submitting.

Back to top

The schema defined on your model can be the schema object itself, or a function that returns a schema object. This can be useful if you're referencing variables that haven't been initialized yet.

The following default editors are included:

Main attributes

For each field definition in the schema you can use the following optional attributes:

  • type

    The editor to use in the field. Can be a string for any editor that has been added to Backbone.Form.editors, such as the built-in editors (e.g. { type: 'TextArea' }), or can be a constructor function for a custom editor (e.g. : { type: MyEditor }).

    If not defined, defaults to 'Text'.

  • title

    Defines the text that appears in a form field's <label>. If not defined, defaults to a formatted version of the camelCased field key. E.g. firstName becomes First Name. This behaviour can be changed by assigning your own function to Backbone.Form.Field.prototype.createTitle.

    Title is escaped by default, to allow using special characters such as < and >, as well as to prevent possible XSS vulnerabilities in user generated content.

  • titleHTML

    This by default will not be escaped, allowing you to use HTML tags. Will override title if defined.

  • validators

    A list of validators. See Validation for more information.

  • help

    Help text to add next to the editor.

  • editorClass

    String of CSS class name(s) to add to the editor.

  • editorAttrs

    A map of attributes to add to the editor, e.g. { maxlength: 30, title: 'Tooltip help' }.

  • fieldClass

    String of CSS class name(s) to add to the field.

  • fieldAttrs

    A map of attributes to add to the field, e.g. { style: 'background: red', title: 'Tooltip help' }.

  • template

    Name of the template to use for this field. See Customising templates for more information.

Main events

Every editor fires the following events:

  • change

    This event is triggered whenever something happens that affects the result of editor.getValue().

  • focus

    This event is triggered whenever this editor gains focus, i.e. when an input within this editor becomes the document.activeElement.

  • blur

    This event is triggered whenever this editor loses focus, i.e. when an input within this editor stops being the document.activeElement.

Besides these three, editors can implement custom events, which are described below.

Back to top

Creates a normal text input.

  • dataType

    Changes the type="text" attribute. Used for HTML5 form inputs such as url, tel, email. When viewing on a mobile device e.g. iOS, this will change the type of keyboard that is opened. For example, tel opens a numeric keypad.

Creates and populates a <select> element.

  • options

    Options to populate the <select>.

    Can be any of:

    • String of HTML <option>s
    • Array of strings/numbers
    • An array of option groups in the form [{group: 'Option Group Label', options: <any of the forms from this list (except the option groups)>}]
    • Array of objects in the form { val: 123, label: 'Text' }
    • A Backbone collection
    • A function that calls back with one of the above
    • An object e.g. { y: 'Yes', n: 'No' }

    By default, options values and labels are escaped when rendered, to allow using special characters such as < and >, as well as to prevent possible XSS vulnerabilities in user generated content. Since Select HTML elements can't contain arbitrary HTML inside of them, there is no option on Select to NOT encode the text. Custom Editors that extend Select should factor in the possibility of labels that contain HTML.

    Backbone collection notes

    If using a Backbone collection as the options attribute, models in the collection must implement a toString() method. This populates the label of the <option>. The ID of the model populates the value attribute.

    If there are no models in the collection, it will be fetch()ed.

Methods

  • setOptions()

    Update the options in the select. Accepts any of the types that can be set in the schema options.

Examples

var schema = {
    country: { type: 'Select', options: new CountryCollection() }
};

var schema = {
    users: { type: 'Select', options: function(callback, editor) {
        users = db.getUsers();

        callback(users);
    }}
};

// Option groups (each group's option can be specified differently)
var schema = {
    options: [
        { group: 'Cities', options: ['Paris', 'Beijing']},
        { group: 'Countries', options: new Collection(objects)},
        { group: 'Food', options: '<option>Bread</option>'}
    ]
};

Creates and populates a list of radio inputs. Behaves the same way and has the same options as a Select.

When the Radio's is given options as an array of objects, each item's label may be replaced with labelHTML. This content will not be escaped, so that HTML may be used to style the label. If it uses object syntax, this option is not possible.

Examples

var schema = {
    radios: {
        type: "Radio",
        options: [
            { label: "<b>Will be escaped</b>", val: "Text is not bold, but <b> and </b> text is visible"},
            { labelHTML: "<b>Will NOT be escaped</b>", val: "Text is bold, and HTML tags are invisible"}
        ]
    }
};

var schema = {
    radios: {
        type: "Radio",
        options: {
            value1: "<b>Text is not bold, but <b> and </b> text is visible</b>",
            value2: "There is no way to unescape this text"
        }
    }
};

Creates and populates a list of checkbox inputs. Behaves the same way and has the same options as a Select. To set defaults for this editor, use an array of values.

Checkboxes options array has the same labelHTML option as Radio.

The Object editor creates an embedded child form representing a JavaScript object.

Attributes

  • subSchema

    A schema object which defines the field schema for each attribute in the object.

Events

  • <key>:<event>

    Events fired by editors within this Object editor will bubble up and be fired as <key>:<event>.

Examples

var schema = {
    address: {
      type: 'Object',
      subSchema: {
        street: {},
        zip: { type: 'Number' },
        country: { type: 'Select', options: countries }
      }
    }
};

addressEditor.on('zip:change', function(addressEditor, zipEditor) {
    console.log('Zip changed to "' + zipEditor.getValue() + '".');
});

Used to embed models within models. Similar to the Object editor, but adds validation of the child form (if it is defined on the model), and keeps your schema cleaner.

Attributes

  • model

    A reference to the constructor function for your nested model. The referenced model must have it's own schema attribute.

Events

  • <key>:<event>

    Events fired by editors within this NestedModel editor will bubble up and be fired as <key>:<event>.

Examples

var schema = {
    address: { type: 'NestedModel', model: Address }
};

addressEditor.on('zip:change', function(addressEditor, zipEditor) {
    console.log('Zip changed to "' + zipEditor.getValue() + '".');
});

Creates <select>s for date, month and year.

  • yearStart

    First year in the list. Default: 100 years ago.

  • yearEnd

    Last year in the list. Default: current year.

Extra options

You can customise the way this editor behaves, throughout your app:

var editors = Backbone.Form.editors;

editors.Date.showMonthNames = false; //Defaults to true
editors.Date.monthNames = ['Jan', 'Feb', ...]; //Defaults to full month names in English

Creates a Date editor and adds <select>s for time (hours and minutes).

  • minsInterval

    Optional. Controls the numbers in the minutes dropdown. Defaults to 15, so it is populated with 0, 15, 30, and 45 minutes.

Creates a list of items that can be added, removed and edited. Used to manage arrays of data.

This is a special editor which is in a separate file and must be included:

<script src="backbone-forms/distribution/editors/list.min.js" />

Modal Adapter

By default, the List editor uses modal views to render editors for Object or Nested Model item types. To use the default modal adapter, you must include the Backbone.BootstrapModal library on the page:

<script src="backbone-forms/distribution/adapters/backbone.bootstrap-modal.min.js" />

You may also specify your own modal adapter, as long use you follow the interface of the Backbone.BootstrapModal class.

var MyModalAdapter = Backbone.BootstrapModal.extend({
    // ...
});

Form.editors.List.Modal.ModalAdapter = MyModalAdapter;

If you prefer non-modal editors, you may override the default list editors like so:

// Use standard 'Object' editor for list items.
Form.editors.List.Object = Form.editors.Object;

// Use standard 'NestedModel' editor for list items.
Form.editors.List.NestedModel = Form.editors.NestedModel;

See an editable demo of using the Nested Model, List and Modal Adapter together.

Attributes

  • itemType

    Defines the editor that will be used for each item in the list. Similar in use to the main 'type' schema attribute. Defaults to 'Text'.

  • confirmDelete

    Optional. Text to display in a delete confirmation dialog. If falsey, will not ask for confirmation.

  • itemToString

    A function that returns a string representing how the object should be displayed in a list item.

    Optional, but recommended when using itemType 'Object'. When itemType is 'NestedModel', the model's toString() method will be used, unless a specific itemToString() function is defined on the schema. If your Object keys can contain HTML, you may be vulnerable to XSS attacks (Bug #516):

    function itemToString(value) {
        var safeString = '';
        Object.keys(value).forEach(function(key) {
            safeString += key + ':' + $('<div>').html(value[key]).text() + '<br/>';
        });
    
      return safeString;
    }
    
    var schema = {
        users: {
            type: 'List',
            itemType: 'Object',
            itemToString: itemToString
        }
    };

    See a working example here.

  • itemClass

    A class to use instead of List.Item.

    The default class wraps each editor in a <div> and adds a "delete" button on each row. Provide this argument and List will use your custom item class, allowing you to customize this behavior.

  • addLabel

    Label of the button used to add a new item in the list. Defaults to 'Add'.

Events

  • add

    This event is triggered when a new item is added to the list.

  • remove

    This event is triggered when an existing item is removed from the list.

  • item:<event>

    Events fired by any item's editor will bubble up and be fired as item:<event>.

Examples

function userToName(user) {
    return user.firstName + ' ' + user.lastName;
}

var schema = {
    users: { type: 'List', itemType: 'Object', itemToString: userToName }
};

listEditor.on('add', function(listEditor, itemEditor) {
    console.log('User with first name "' + itemEditor.getValue().firstName + '" added.');
});

listEditor.on('item:focus', function(listEditor, itemEditor) {
    console.log('User "' + userToName(itemEditor.getValue()) + '" has been given focus.');
});

listEditor.on('item:lastName:change', function(listEditor, itemEditor, lastNameEditor) {
    console.log('Last name for user "' + itemEditor.getValue().firstName + '" changed to "' + lastNameEditor.getValue() +'".');
});

Back to top

There are 2 levels of validation: schema validators and the regular built-in Backbone model validation. Backbone Forms will run both when form.validate() is called. Calling form.commit() will run schema level validation by default, and can also run model validation if { validate: true } is passed.

Schema validation

Validators can be defined in several ways:

  • As a string - Shorthand for adding a built-in validator. You can add custom validators to this list by adding them to Backbone.Form.validators. See the source for more information.
  • As an object - For adding a built-in validator with options, e.g. overriding the default error message.
  • As a function - Runs a custom validation function. Each validator the following arguments: value and formValues.
  • As a regular expression - Runs the built-in regexp validator with a custom regular expression.

Built-in validators

  • required: Checks the field has been filled in.
  • number: Checks it is a number, allowing a decimal point and negative values.
  • range: Checks it is a number in a range defined by min and max options. Message if it is not a number can be set with the numberMessage option.
  • email: Checks it is a valid email address.
  • url: Checks it is a valid URL.
  • match: Checks that the field matches another. The other field name must be set in the field option.
  • regexp: Runs a regular expression. Requires the regexp option, which takes a compiled regular expression or a string value. Setting the match option to false ensures that the regexp does NOT pass. If you set the regexp option to a string, it will also pass the flags option, if set, directly to the RegExp constructor's 'flags' argument - see below / demo.

Built-in Validators Demo

Examples

var schema = {
    //Built-in validator
    name: { validators: ['required'] },

    //Multiple built-in validators
    email: { validators: ['required', 'email'] },

    //Built-in editors with options:
    password: { validators: [
        { type: 'match', field: 'passwordConfirm', message: 'Passwords must match!' }
    ] },

    //Regular expression
    foo: { validators: [/foo/] },

    //Regular expression with flags - if using flags, regexp must be string
    baz: {
        validators: [{
            type: 'regexp',
            regexp: 'baz',
            flags: 'i',
            message: 'Must type \'baz\' - case insensitive'
        }]
    },

    //Custom function
    username: { validators: [
        function checkUsername(value, formValues) {
            var err = {
                type: 'username',
                message: 'Usernames must be at least 3 characters long'
            };

            if (value.length < 3) return err;
        }
    ] }
};

Handling errors

Error messages will be added to the field's help text area, and a customisable bbf-error class will be added to the field element so it can be styled with CSS.

Validation runs when form.commit() or form.validate() are called. If validation fails, an error object is returned with the type (validator that failed) and customisable message:

//Example returned errors from form validation:
{
    name:   { type: 'required', message: 'Required' },              //Error on the name field
    email:  { type: 'email', message: 'Invalid email address' },    //Error on the email field
    _others: ['Custom model.validate() error']                      //Error from model.validate()
}

Customising error messages

After including the Backbone Forms file, you can override the default error messages.

{{mustache}} tags are supported; they will be replaced with the options passed into the validator configuration object. {{value}} is a special tag which is passed the current field value.

Backbone.Form.validators.errMessages.required = 'Please enter a value for this field.';

Backbone.Form.validators.errMessages.match = 'This value must match the value of {{field}}';

Backbone.Form.validators.errMessages.email = '{{value}} is an invalid email address.';

You can also override the error message on a field by field basis by passing the message option in the validator config.

Model validation

If your models have a validate() method the errors will be added to the error object. To make the most of the validation system, the method should return an error object, keyed by the field object. If an unrecognised field is added, or just a string is returned, it will be added to the _others array of errors:

var User = Backbone.Model.extend({
    validate: function(attrs) {
        var errs = {};

        if (usernameTaken(attrs.username)) errs.username = 'The username is taken';

        if (!_.isEmpty(errs)) return errs;
    }
});

Schema validators

Forms provide a validate method, which returns a dictionary of errors, or null. Validation is determined using the validators attribute on the schema (see above).

If you model provides a validate method, then this will be called when you call Form.validate. Forms are also validated when you call commit. See the Backbone documentation for more details on model validation.

Example

//Schema definition:
var schema = {
    name: { validators: ['required'] }
};

var errors = form.commit();

Back to top

Backbone Forms comes with a few options for rendering HTML. To use another template pack, such as for Bootstrap, just include the .js file from the templates folder, after including backbone-forms.js.

You can change all the default templates by copying the included distribution/templates/bootstrap.js file and adapting that. Placeholders are the data-xxx attributes, e.g. data-fieldsets, data-fields and data-editors.

Alternate field templates

If only certain fields need a different template this can be done by providing the template in the schema:

var altFieldTemplate = _.template('<div class="altField" data-editor></div>');

var form = new Backbone.Form({
  schema: {
    age: { type: 'Number' },        //Uses the default field template
    name: { template: altFieldTemplate }  //Uses the custom template
  }
});

100% custom forms

To customise forms even further you can pass in a template to the form instance or extend the form and specify the template, e.g.:

<script id="formTemplate" type="text/html">
    <form>
        <h1><%= heading1 %></h1>

        <h2>Name</h2>
        <div data-editors="firstName"><!-- firstName editor will be added here --></div>
        <div data-editors="lastName"><!-- lastName editor will be added here --></div>

        <h2>Password</h2>
        <div data-editors="password">
            <div class="notes">Must be at least 7 characters:</div>
            <!-- password editor will be added here -->
        </div>
    </form>
</script>
var form = new Backbone.Form({
    template: _.template($('#formTemplate').html()),
    model: new UserModel(), //defined elsewhere
    templateData: {heading1: 'Edit profile'}
});

Back to top

You can add editors by themselves, without being part of a form. For example:

var select = new Backbone.Form.editors.Select({
    model: user,
    key: 'country',
    options: getCountries()
}).render();

//When done, apply selection to model:
select.commit();

If you are using a schema with nested attributes (using the Object type), you may want to include only some of the nested fields in a form. This can be accomplished by using 'path' syntax as in the example below.

However, due to Backbone's lack of support for nested model attributes, getting and setting values will not work out of the box. For this to work as expected you must adapt your model's get() and set() methods to handle the path names, or simply use DeepModel which will handle paths for you automatically.

var Model = Backbone.DeepModel.extend({
    schema: {
        title: 'Text',
        author: { type: 'Object', subSchema: {
            id: 'Number',
            name: { type: 'Object', subSchema: {
                first: 'Text',
                last: 'Text'
            }}
        }}
    }
});

var form = new Backbone.Form({
    model: new Model,
    fields: ['title', 'author.id', 'author.name.last']
}).render();

The following shorthand is also valid:

var Model = Backbone.DeepModel.extend({
    schema: {
        title: 'Text',
        'author.id': 'Number',
        'author.name.first': 'Text'
    }
});

var form = new Backbone.Form({
    model: new Model
});

Writing a custom editor is simple. They must extend from Backbone.Form.editors.Base.

var CustomEditor = Backbone.Form.editors.Base.extend({

    tagName: 'input',

    events: {
        'change': function() {
            // The 'change' event should be triggered whenever something happens
            // that affects the result of `this.getValue()`.
            this.trigger('change', this);
        },
        'focus': function() {
            // The 'focus' event should be triggered whenever an input within
            // this editor becomes the `document.activeElement`.
            this.trigger('focus', this);
            // This call automatically sets `this.hasFocus` to `true`.
        },
        'blur': function() {
            // The 'blur' event should be triggered whenever an input within
            // this editor stops being the `document.activeElement`.
            this.trigger('blur', this);
            // This call automatically sets `this.hasFocus` to `false`.
        }
    },

    initialize: function(options) {
        // Call parent constructor
        Backbone.Form.editors.Base.prototype.initialize.call(this, options);

        // Custom setup code.
        if (this.schema.customParam) this.doSomething();
    },

    render: function() {
        this.setValue(this.value);

        return this;
    },

    getValue: function() {
        return this.$el.val();
    },

    setValue: function(value) {
        this.$el.val(value);
    },

    focus: function() {
        if (this.hasFocus) return;

        // This method call should result in an input within this editor
        // becoming the `document.activeElement`.
        // This, in turn, should result in this editor's `focus` event
        // being triggered, setting `this.hasFocus` to `true`.
        // See above for more detail.
        this.$el.focus();
    },

    blur: function() {
        if (!this.hasFocus) return;

        this.$el.blur();
    }
});

Notes:

  • The editor must implement getValue(), setValue(), focus() and blur() methods.
  • The editor must fire change, focus and blur events.
  • The original value is available through this.value.
  • The field schema can be accessed via this.schema. This allows you to pass in custom parameters.

master

  • Add ability to skip wrapping field for certain editors via the noField property
  • Allow fieldsets to be defined on model (fonji)
  • Add submitButton to form constructor. Adds a submit button with given text.
  • No longer require jquery from within the CommonJS module. NOTE: You must now set Backbone.$ yourself if using CommonJS e.g. browserify
  • Fix CommonJS backend issues (ndrsn)
  • Added the number validator
  • Support specifying fieldsets on the Form prototype
  • Support specifying field and fieldset templates in their prototypes; allows extending Form, Field and Fieldset to create custom forms
  • Support regexp validator as string (gregsabia)
  • Fix bootstrap3 class list name #329
  • Add 'match' option to regexp validator

0.14.1

  • Bugfix - incorrect versioning in files for 0.14.0 release - update and tag

0.14.0

  • Add Bootstrap 3 templates (powmedia)
  • Being consistent with throwing Errors rather than strings (philfreo)
  • Save templateData when passed as an option (BradDenver)

0.13.0

  • Confirming compatibility with Backbone 1.1.0 (still supporting 1.0.0)
  • Fix form.commit() to only run model-level validation if {validate:true} passed (cmaher)
  • Allow for setting defaults on the prototype (patbenatar)
  • Make it possible to trigger editor events with custom arguments (mvergerdelbove)
  • Give checkboxes unique IDs in groups (exussum12)
  • Allow passing an object to Select (lintaba)
  • Add checkbox array grouping (exussum12)
  • Fix checkboxes and radio 'name' attributes (#95)
  • Allow field template to be defined in schema
  • Fix overriding List modal templates in Bootstrap template pack
  • Add ability to unset checkbox (exussum12)
  • Fix change event on number field when using spinner (clearly)
  • Render hidden inputs, without labels
  • Remove type attribute from TextAreas (#261)
  • Fix error when using template files without list.js (philfreo)
  • Allow overriding 'step' attribute in Number editor (jarek)
  • Allow most falsey values as an Editor value (ewang)

0.12.0

  • Update for Backbone 1.0
  • Overhaul templating and rendering
  • List: Set focus on newly added simple list items
  • Select: Add option group support (khepin)

0.11.0

  • Update for Backbone 0.9.10
  • Pass editor instance as second parameter to Select options function
  • Fix for jQuery 1.9
  • Don't show if schema title===false (philfreo)
  • Fix change event on radio editor (DominicBoettger)
  • Fix model errors not being return by validate() (mutewinter)
  • Setting value with setValue only from form.schema (okhomenko)
  • Some smaller optimisation and fixes according to jsHint (MarcelloDiSimone)
  • Add Form.setValue(key, val) option for arguments (lennym)
  • Support ordering years in descending order in Date field (lennym)
  • Allow the Number field type to accept decimal values (philfreo)
  • Added 'backbone-forms' as a dependency to the AMD wrapper for templates. (seanparmelee)
  • Allow use of required validator with checkbox fields (lennym)
  • Make Form.Field template rendering context overrideable (drd)
  • Fix a mismatched button element in the bootstrap.js template file. (there4)
  • Fix AMD editors that must have Backbone Forms (philfreo)
  • Skip undefined properties when setting form value from model.toJSON() (jgarbers)
  • Add listItemTemplate option to list editors (philfreo)
  • Fix NestedModel values being overridden by defaults (#99)
  • Add Select.setOptions() method to change options on demand
  • AMD improvements (see issue #77)
  • Add 'change', 'focus' and 'blur' events (DouweM)
  • Fix: #72 Hitting 'Enter' being focused on any text field in examples deletes nested "notes"
  • Pressing enter in a list now adds a new item to the bottom of the list (Juice10)
  • Customization of List Template & Tweaked default templates (philfreo)
  • Fix not rendering of hidden fields (#75) (DouweM)
  • DateTime editor:
    • Convert strings to dates
    • Remove built-in Date editor before removing self
  • Email validator should accept "+" sign (#70)

0.10.0

  • update build scripts & package.json for jam packaging (dstendardi)
  • Fields with options, such as Select, should handle 0 as value (torbjorntorbjorn)
  • Update backbone.bootstrap-modal adapter
  • Refactor rendering.
    • tags are now defined in the template.
    • Where a template is used, (e.g. advanced editors, field etc.), the entirety of the HTML is now defined in the template to make custom templating easier.
    • All templates must now have a main 'parent' element.
  • Create new List, Date and DateTime editors that don't rely on jQuery UI.
    • You will still need to use jQuery UI editors for the calendar.
    • For list items of type Object and NestedModel you must include a modal adapter, such as the included Bootstrap Modal one. Should create one for jQuery UI.
  • Improve the way dependencies are defined and module is exported for browser & CommonJS
  • Add underscore dependency to AMD version
  • Use buildify for building distribution files.
  • Rename jQuery UI editors to jqueryui.List, jqueryui.Date, jqueryui.DateTime. These may be moved to a separate repository soon.
  • Fix #65 Number editor Firefox NaN bug
  • Fix bug with hidden fields (jeffutter)
  • Fix AMD distribution bug (ikr)

Required changes when upgrading:

  • List editor:
    • Change 'listType' to 'itemType' in schema definition.
    • Make sure you have a modal adapter included if using Object and NestedModel itemTypes. See the List editor section.

0.9.0

  • Added ability to use a custom template compiler (geowa4)
  • Added distribution files (development and minified production versions)
  • Added AMD-compatible version (development and minified production versions)

backbone-forms's People

Contributors

alexstrat avatar ansman avatar braddenver avatar clearly avatar douwem avatar eschwartz avatar ewang avatar exussum12 avatar ezheidtmann avatar glenpike avatar iabw avatar integral avatar janpaul123 avatar khepin avatar lennym avatar lincolndbryant avatar lintaba avatar marcellodisimone avatar markmarkoh avatar miketonks avatar mikl avatar millerren avatar mjtamlyn avatar ndrsn avatar nfvs avatar okhomenko avatar philfreo avatar powmedia avatar rafaelmaza avatar vkareh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

backbone-forms's Issues

Schema names

I just spent an hour debugging why a form didn't show up and it turns out that I had used Textarea instead of TextArea.

So I was wondering a few things:

  • Could these names be normalized (lower-case) in the class code and input is run through .toLowerCase()?
  • Could you guys test if the schema used actually exists (somewhere along the lines of defensive coding), because otherwise the page dies with undefined is not a function.

Ability to know when form changes

Currently if implementing an autosave feature, you'd have to do something like

$( form.el ).live( 'input, select', 'change', function( event ) {
  form.commit()
  ...
})

However this is somewhat tedious, and it doesn't easily allow you to "watch" when lists have items added, etc...

It would be great if there was a way to observe the form object for user changes.

Number editor

On the setValue an empty string from a default will come up as NaN when the form loads.

Perhaps we can add near line 1050:

if(_.isNaN(value)) value = null;

But maybe it can be integrated into this line:
value = value === null ? null : parseFloat(value, 10);

But I'm not sure how.

Cannot find module 'jquery'

Hi,

I use brunch.io and I would like use backbone-forms but I've got two error with Require.js

Uncaught Error: Cannot find module 'jquery'
Uncaught TypeError: Cannot call method 'template' of undefined

Someone can help me ?

Best practice for file upload

Hi!

My model has a field of type File. How can I organize a file upload through backbone-forms? Is it possible? Point me in the right direction please. I'm using django-tastypie.

Thanks,
Vitaliy

Uncaught TypeError: Cannot call method 'getHours' of undefined

Hello,

First off, thank you for creating backbone-forms. I've forked it and have run into a problem with DateTime. Not sure if I'm just not getting it or its a bug. The exact error i'm getting is with DateTime in the schema.

"Uncaught TypeError: Cannot call method 'getHours' of undefined"

You can clone my fork here to reproduce. https://github.com/jamescharlesworth/backbone-forms. Just load the index.html page and you should see the error.

Thank you,

James

nested form inside list

Hi,

Is there any way to nest a form inside of a list?

For example:

schema: {
people: {
type: 'List',
'LISTFIELDS' => 'firstname, lastname, city, state'?
}
}

Is there any way to do something like the above?

Thanks a bunch!

Multiple forms with the same attribute names

If you have multiple forms that have some attributes with the same name, then elements with duplicate IDs are created. Perhaps the form element IDs should be prefixed with the model id/cid?

Recommended way to use list.js with RequireJS

I'm using your AMD compatible backbone-forms.amd but can you let me know the recommended way to include list.js with that?

Also it's hard to NOT use your AMD-compatible version. If I wanted to use the non-amd version using a RequireJS shim it's hard because your non-amd version checks for the existence of the "require" function :(. If you just want to detect "is this a browser" would be better to check FOR a window object.

Fix the 'name' attribute in Object and NestedModel editors

Required in case a form is submitted via normal browser POST

Option 1:

  • Nested inputs prefixed with the main field name

Option 2:

  • No name attribute on nested fields, but have a hidden input with the main field name, that contains the value for the object/nested model

Design advice: specifying data source for an autocomplete editor

Thanks for this library.

I’m making use of it in a project, and I extended Backbone.Form.editors.Base to create an Autocomplete editor that uses jQuery UI’s autocomplete. Usage example:

class Move extends Backbone.Model
  schema:
    person_id:
      title: "Person"
      type: "Autocomplete"
      collection: "Roster.people"

It works nicely, and I’m hoping to be able to contribute this back to the community (tests already written), but there’s a design flaw: the mechanism of specifying the data source.

I originally passed the collection in directly, but then I ran into loading order problems. Now it uses the dreaded eval to find the collection. It’s okay for my purposes, but wouldn’t be happy releasing it that way for general usage. Apart from being a poor solution, it’s also limited in that there can only be one backing collection, so I can’t use, say, a subset of the People collection if I need to.

Does anyone have thoughts on how I can make a clean interface so other people can integrate this type of editor? Is it just not a good fit for the design of Backbone Forms? Here are ideas I’ve considered and why I think they don’t work:

  • passing in a function for the data source: editor could then only find objects in global scope
  • specifying a datasource or something that could be passed in when constructing the Form: an Editor has no access to the Form that contains it

An extra benefit for me to solving this would be that I can add validation that depends on an entered value being in a collection determined at runtime.

I debated whether this was the venue for this sort of question or whether Stack Overflow was better. Sorry if I chose incorrectly.

Allow form.commit() to trigger only one change event on model

When calling commit() on a form with more than one updated field, change is triggered on the associated model for each changed attribute.

Backbone allows you to set() many attributes at once on a model. I think this triggers one change event, even when more than one attribute is updated. This allows you to listen to the change event on a model and fire a function.

Should we build a hash of attributes to change and set them all at once in the commit() vs once per field?

My current use case is having a SearchForm with an associated SearchRequestModel. A ResultsCollection references an instance of the SearchRequestModel and has a function bound to the change event that calls a fetch, using the SearchRequestModel's attributes as the parameters to send in the fetch.

Basically, when "submitting" the form, I call commit() on the form, triggering the change on the request model, which triggers the collection's fetch.

Clearing before render()

Re-rendering the Form actually appends the form markup to its element, it doesn't clear its element's markup before re-rendering.

Generally, I would expect it to clear before re-rendering. Do you have a strong preference for it to not do that?

Submit button, <form> tag, and fieldsets vs forms

Hi Charles,

First off, I'm enjoying this library a great deal so far - it fills a definite gap in Backbone usage. Thanks for getting the ball rolling. I have a few questions, so I'll open different issues for each.

In general, the markup generated by a Backbone.Form instance is more like a set of fields (a fieldset?), than a whole form; it has a root <ul> tag rather than <form>, and doesn't yet have facility to including a submit button or cancel button/link. I find myself wrapping it inside another Backbone view class that provides the encloding <form> element and input buttons, but it would be nice if a Form instance could provide all the markup for a <form>. What do you think?

Live model binding

It would be useful to have an option of live model bindings to form. It would be real MVC .

lists as textfields

First of all,
thanks for this precious tool, it works fine and it was very helpful for my application.

I would propose a little change on lists, which maybe would make things even more usable.

Elements in a list are shown as span elements. When the user needs to add/delete/modify a popup is opened with jquery-ui. The popup is not always the best solution, sometimes it's not nice, sometimes it can raise up troubles (for instance if the form is already in a popup box, then you must open the jquery dialog as a child of the popup box).

Maybe a good solution is not to show list elements as 'span' but as input fields with the 'delete' icon on the right. And when hitting the 'add' button, simply an input row is added.

Does it make sense?
good bye.
Daniele

Support backbone-relational

Hi,

https://github.com/PaulUithol/Backbone-relational

ItemText.Model = Backbone.RelationalModel.extend({

    schema: {
        item:  {
            type: 'NestedModel',
            model: Item.Model
        },
        text:  { type: 'TextArea',validators: ['required'] }
    },
    relations:[
        {
            type:Backbone.HasOne,
            key:'item',
            relatedModel:Item.Model,
            includeInJSON:true
        }
    ]
});

Schema for Item didn't work. Because relational change model attributes. See...

Without backbone-relational

attributes: Object
    id: "25"
    item: Object
        id: "25"
        layer: "/api/v1/layers/46/"
        name: "XXXXXXXXXXXX"
        position_x: 23
        position_y: 27
        position_z: 0
        resource_uri: "/api/v1/items/25/"  
        __proto__: Object
    resource_uri: "/api/v1/texts/25/"
    text: "qqqqq"

With backbone relational:

attributes: Object
    id: "25"
    item: Object
        attributes: Object
            id: "25"
            layer: "/api/v1/layers/46/"
            name: "XXXXXXXXXXXX"
            position_x: 23
            position_y: 27
            position_z: 0
            resource_uri: "/api/v1/items/25/"
            __proto__: Object
        changed: Object
        cid: "c16"
        collection: Object
        id: "/api/v1/items/25/"
        __proto__: Object
    resource_uri: "/api/v1/texts/25/"
    text: "qqqqq"

Number Validation

When using type Number the text input should not preventDefault on backspace, delete, arrow etc.

I changed near line 938 as follows:

var char = String.fromCharCode(event.charCode);
//check for backspace, arrows, etc...
if( event.charCode <= 46 ) char = "";

var newVal = this.$el.val() + char;

Add examples

  • Simple form
  • Complex form
  • jQuery UI editors
    • Using List editor by itself for managing collections
  • Custom templates
  • Custom editor

Better version of 'Text'

I've been using backbone-forms to make forms for iOS, so there's a significant use of <input type="blah"> where blah can be tel, email etc.

At the moment you have to make a subclass of editors.Text and set the type (in the same way as editors.Password works). It would be nicer if you can pass a type attribute or similar to override it on a editors.Text instance. Alternatively, we should go through the list of html input types and provide them all.

Separate out the file and write a builder.

backbone-forms.js is now over 1000 lines long, even longer than core.js in jQuery. It would be nice to separate Form, Field, helpers, validators, Editors etc out in to separate js files, despite their interdependency and create a script which builds the file into a single, minified js file for deployment.

We could also then provide versions with/without the jQuery dependant editors, and a version packaged as a require.js module.

delete unneeded commas

Hi there,

There are some unneeded commas which would throw some errors in old msie browsers i think.

550 - after 'textarea'
740 - after }
793 - after }

Best regards

martin

Styling & Layout (uni-form?)

There's a few issues I'm trying to overcome here with the html layout of the forms generated. I'd like to be able to group fields together into fieldsets, add headings and help text to those fieldsets and on some occasions even produce a custom template for where the editors/fields should appear.

It would be nice if the html outputted complied with the uni-form standard (http://sprawsm.com/uni-form/). I've used the django plugin for this quite a lot and it's really easy to adapt to your needs. It also comes with some pretty css for free which is always good.

I'm quite happy to do some development on this, I just wanted to get some opinions before I dive in and diverge. Is there a mail list or IRC for backbone-forms anywhere?

Validation of NestedModels in List jquery-ui-editors

It seems that the nested models are not being "committed" from the List modal. This means that if the schema does not contain validation but the model does, the nested modal will be saved to the main model even though it is not valid (on the model).

Seems like an easy enough fix, we just force the embedded model to commit. Near line 392 in jquery-ui-editors:
var saveAndClose = function() {
var errs = editor.validate();
if (errs) return;

    //validate against the model too
    if(listType == "NestedModel"){
        errs = editor.commit();
        if (errs) return;
    }

However, the NestedModel editor has this line in its commit function near line 1500 in backbone-forms.js. This will kick an error from the modal.

return editors.Object.prototype.commit.call(this);

Any ideas on how to insure the List jquery-ui-editor for NestedModels will validate against the model?

Support for multiple templates

It'd be nice if there was an easy way to have different Forms use different templates. For example, you might want a bootstrap template that is a .form-horizontal and a .form-vertical (right now bootstrap.js hardcodes in .form-horizontal), but you also might want much more extreme changes.

Could work like:

this.form = new Backbone.Form({
  model: this.model,
  template: 'custom_form1' 
});

Use schema in form for creating a new instance of a model

I must be missing something...

I'm trying to create a Backbone form for a new instance of a particular model which has a schema defined, but because it's not saved yet it doesn't have an ID. After scanning through the README I don't see a way to actually do this.

What do I need to specify for the model parameter when calling new Backbone.Form({model: ????})

(I've tried this.model but that just results in a 'can't find schema' error.)

Existing form

A while ago, I started a fork of this rep to implement its features on existing form so it doesn't only generate forms but take existing ones and apply validation, plugins... (I can't really do a pull request as it was too long ago and it would be more complicated to merge than to rewrite the code).

Would you be interested in this feature? I'd be happy to write the code. It basically adds a el attribute - a jquery object or a selector - to the schema definition. So you can do any of this:

      schema: {
        name:      $('#foo'),
        email:     '#email',
        start:     { el:  $('#start') },
        end:       { el:  '#start' }
    }

It automatically detects what the input is and set the rest of the schema accordingly. Though it can be overwritten by being explicit in the schema definition.

Numeric editor does not work

Numeric editor has invalid char processing. It does not works at all.

Line 624:

You should replace event.keyCode to event.charCode

Generic Object Editor

When I try and use an object editor for an object property of my model I get:

Uncaught Missing required 'schema.subSchema' option for Object editor

I would expect to see some kind of key value pair editor where I can edit each property of the object and add or remove properties.

list dependencies

Aside from backbone, it seems jquery-ui is needed heavily for certain editors.

Can you list the exact dependencies in the readme (for jquery-ui and jquery)?

version number

there is currently no way to distinguish between file versions other than doing a file diff.

so could you add a docblock like this:

//
// Backbone-Forms v*.*.*
// 
// 
// Copyright (c) etc.
// Licensed under the etc...License.
//

setValue for NestedModel field

Hi,

Help me please.

I have:
schema: {
item: {
type: 'NestedModel',
model: Item.Model
},
text: { type: 'TextArea',validators: ['required'] }
}

I want to change a field in item fields,

this.form.setValue({item:{position_x:5,position_y:6}})

This action reset all other fields for item nested model (name, color, shape etc.)

How I can do this?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.