BerryJS Field Guide

NOTE: This is a beta version, possibly still containing bugs and some parts of api may still change slightly.

What is it?

Berry is an extensible JavaScript/jQuery library with an included set of CSS rules.

The core library does very little besides establish the framework without at least one plugin. Each input type is defined with a plugin allowing for many more input types than are normally available in plain html and more can be created as the need arises.

The basics include hidden, text, textarea, select, checkbox, radio, and password.

HTML5 adds quite a few more but it is difficult to rely on them since support in older browsers is sketchy at best, this is where Berry comes in. With the proper plugin you can trust that the input will look, act and validate correctly. Its even possible to create input types that don't exist in any spec but act in similar and predictable ways.


Getting Started

Dependencies - Berry has two hard dependencies that needed. The first being jquery (or zepto) and the second being hogan.js. Strictly speaking the compile portion of hogan is not needed.

<script src='http://twitter.github.com/hogan.js/builds/3.0.1/hogan-3.0.1.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js'></script>

Next the core berry engine will need to be loaded.

<script type='text/javascript' src='berry.min.js'></script>

And lastly a theme is required - the default theme is based on bootstrap and will also require the css for bootstrap to be included.

<style src='//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css'></style>
<script type='text/javascript' src='bootstrap.berry.js'></script>

So now all together an example of a minimum setup would look something like this

<!DOCTYPE html>
<html>
  <head>
    <style src='//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css'></style>
    <script src='http://twitter.github.com/hogan.js/builds/3.0.1/hogan-3.0.1.js'></script>
    <script src='//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js'></script>
    <script type='text/javascript' src='berry.min.js'></script>
    <script type='text/javascript' src='bootstrap.berry.js'></script>
  </head>
  <body>
  <div class="myForm">
  </div>
  </body>
</html>

Now that we have all of our dependencies included we can begin enjoying the magic of berry!

var options = {};
var myForm = $('.myForm').berry(options);

This will create a form in the element selected with 'selector' defined by your options.


API

toJSON myForm.toJSON([name]);

an object will be returned containing a serialized list of all fields maintained in the Berry tree. If the optional 'name' parameter is supplied then only the value of the field with that name is returned.


destroy myForm.destroy();

this will remove the form and clean up any residuals and remove all events


find myForm.find(path || name);

the Berry field that the path leads to is returned, for first level fields the path is just the name if it is contained within a fieldset the path would be 'fieldset_name.field_name'


validate myForm.validate();

all of the fields are validated and the status of the validation is returned. If a field fails validation the error message is added to that field if the theme supports it. The flag myForm.valid is also set to this status and an array of errors is containted in the myForm.errors attribute;


clearErrors myForm.clearErrors();

this clears the 'valid' flag to true and empties the array of errors



Options

var options = {
  legend: 'My Form',
  name: 'myForm',
  renderer: 'base', //this is the default (base, tabs, wizard, poppins, inline)
};

legend

The legend of the form as it is to be rendered, if left blank no legend will be rendered.

options.legend = 'My Form'

defaults

This is an object that will be used to set defaults on any field that is created, if an attribute is set here and not overridden in the specific field this is the value that will be used

options.defaults = {type: 'select'} // this would set the default type to select

renderer

The default renderer is the basic renderer, and will render forms as you would expect in separate fieldsets. Some other renderers ship with berry, you can find out more about these here. This is a modular component of Berry which means that others can be created.

options.renderer = 'tabs'

name

The name of your form. This can be used to reference the form after it is created. If no name is given one will be generated automatically. A reference to all forms created is maintained in the object Berry.instances. Accesssing a form with the name "myForm" would look like this Berry.instances['myForm']

options.name = 'myForm'

attributes

If attributes is an object then berry populates your form with the values contained in the attributes. If the keyword hash is set then berry attempts to load the form with attributes retrieved in the url hash

options.attributes = {first_name: 'Bob', last_name: 'Person'}

actions

The actions to be included in the form. By default the cancel and save actions are included. For a full list and instructions on creating new actions go here.

options.actions = ['save']

fields

An array of fields that define each field to be included in the form. If no fields are defined then no form is drawn.

options.fields = []


Field Options

var options = { fields: [
  {
    type: 'text',
    name: 'first_name',
    label: 'First Name'
  }
]};

type ['string', null]

This defines the type of form element to render. The default type is a simple text input.

options.fields[0].type = 'text'

name ['string', null]

If this attribute is not set then the name will be set to the internally genderated uuid for this field. The 'name' attribute is set on the field in the html and is used to reference this field in the collection maintained by Berry.

options.fields[0].name = 'first_name'

label ['string', 'bool', null]

If a string is set this will be used as the label on the current field. To hide the label then this can be set to 'false'. The default label that will apply if no label is set will be the index of the field i.e. the first field will have a label of '0'.

options.fields[0].label = 'First Name'

target ['string', null]

The target by default is the form or fieldset that contains the field however Berry can manage fields accross different containers. If a selector string is passed in then the field will be appended to the element that is indicated by the selector.

options.fields[0].target = '.myForm'

value ['text', 'integer', 'bool', 'function']

This is the default value of the field and has lower presidence than the attributes field on the form.

options.fields[0].value = 'Default'

help ['string']

This is the help text that will be shown to a user to guide them in filling out the field. By default no help text will be included.

options.fields[0].help = 'Put your first name here'

columns ['integer']

Fields default to the full with but based on the grid that the theme uses this can be modified on a per field basis. The default bootstrap theme is based on a 12 column grid.

options.fields[0].columns = 12

show ['bool', 'function' 'Berry.conditions']

The show attribute must in one way or another result in a bool indicating if the field should be shown or not. By defualt this is set to 'true', if the value is simply set to false the field will not be shown. If show is set to a function then the function must return a boolean. The last option is to pass an object with the structure of Berry.conditions that is used to dynamically determine if the field should be shown based on the values of other fields.

options.fields[0].show = true

validate ['bool', 'function' 'Berry.conditions']

options.fields[0].validate = true

required ['bool', 'function' 'Berry.conditions']

options.fields[0].required = true

placeholder ['string']

The placeholder attribute sets the placeholder for some field types, for example the 'text' type.

options.fields[0].placeholder = ''

pre ['string']

This sting will be prepended to the field if the theme supports the pre attribute.

options.fields[0].pre = ''

post ['string']

This sting will be appended to the field if the theme supports the post attribute.

options.fields[0].post = ''

options/choices ['array', 'object', 'string', 'function']

The

options.fields[0].options = ''

max ['integer', null]

This field has a different meaning based on the field type and has no effect on many field types. For a field type of 'number' this will set a maximum number that the fields value can be. If the max is set on any field that would normally have its options/choices passed in then the max is used to generate a set of options for that field.

options.fields[0].max = ''

min ['integer', null]

Similar to the max field this field has a different meaning based on the field type and has no effect on many field types. For a field type of 'number' this will set a minimum number that the fields value can be. If the max is set on any field that would normally have its options/choices passed in then the min is used with the max to generate a set of options for that field. If max is set but min is not then min is assumed to be 0 when generating options.

options.fields[0].min = ''

step ['integer', null]

Similar to the max field this field has a different meaning based on the field type and has no effect on many field types. For a field type of 'number' this will set a step number that the fields value will increase/decreases by when using the arrows. If the max is set on any field that would normally have its options/choices passed in then the min is used with the max to generate a set of options for that field. If max is set but step is not then step is assumed to be 1 when generating options.

options.fields[0].step = ''

Field Types


text

This is the default field type that is created if the type is not specified. This will generate an input of type text.

options.fields[0] = {type: 'text', name: ''}

textarea

This will create a textarea with the value as the content.

options.fields[0] = {type: 'textarea', name: ''}

select

This will create a select element generating the options based on the list of options/choices that are passed in.

options.fields[0] = {type: 'select', name: ''}

radio

This will create a collection of radio buttons generated based on the list of options/choices that are passed in.

options.fields[0] = {type: 'radio', name: ''}

checkbox

This will create a checkbox with true states being any of the following: true, 'true' 1, '1', 'on';
The expected true state can also be set with the attribute trueState and the false state can be set with the attribute falseState

options.fields[0] = {type: 'checkbox', name: ''}

fieldset

This field

options.fields[0] = {type: 'fieldset', name: ''}

Fieldsets


fieldset

options.fields[0] = {type: 'fieldset', legend: 'Common Fields' fields: []}

legend / label

For consistancy with other fields you can set either the 'legend' or the 'label' attribute to render the legend for the fieldset. If you set both the 'legend' attribute is priority. If neither is set no legend is drawn for the basic renderer.

options.fields[0] = {type: 'fieldset', legend: 'Common Fields' fields: []}

multiple

options.fields[0] = {type: 'fieldset', legend: 'Common Fields' fields: []}

duplicate

options.fields[0] = {type: 'fieldset', legend: 'Common Fields' fields: []}

multiple.max

This is the maximum number duplications of the fieldset that is aloud.

options.fields[0] = {type: 'fieldset', legend: 'Common Fields' fields: []}

Events


on('event', 'function')

Bind a callback function to an object. The callback will be invoked whenever the event is fired. If you have a large number of different events on a page, the convention is to use colons to namespace them: "poll:start", or "change:selection". The event string may also be a space-delimited list of several events...

berry.on('change:myfield', function(){})

delay('event', 'function', [delay])

This works exatly like the on method except it will only be triggered after the event has not been fired again after the delay timeout. The default delay time is 250ms.

berry.delay('change', function(){}, ['integer'])

trigger('event')

Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be passed along to the event callbacks.

berry.trigger('change')

Built-in Events

The list of built-in Berry events. You're also free to trigger your own events as you see fit. The context is always set to that of the Berry instance triggering the event.

  • initialize

    This event is fired as Berry begins the initialization and is a good place to put set up code.

  • change

    The change event is triggered whenever the value of a field is changed.

  • destroy

    This event is fired when the destroy method is called but before anything has been destroyed.

  • destroyed

    Fires after everything related to the form has been destroyed.


Renderers

Renderers control how a form is drawn and layed out.

basic

The 'basic' renderer will create the form in and fieldsets in the normal linear way that you would expect.


tabs

This renderer will divide any fieldsets into separate tabs with the legends of each fieldset as the tab titles.


wizard

This renderer will divide any fieldsets into separate sections with the legends of each fieldset as the steps in the wizard and will require you to finish them in order and validate before moving on. Actions will also be create automatically for stepping through and saving.


poppins

The poppins renderer handles the form differently, this will look for elements with the class poppins and a name matching the name of one of the fields, the value of that field will then be set to the contents of that element and set that element up to have a popup allow you to edit that value when it is clicked.


Conditions

{
  "label": "Reason",
  "name": "reason",
  "type": "text",
  "show": {
    "matches": {
      "name": "candy",
      "value": "Chocolate"
    },				
    "not_matches": {
      "name": "candy",
      "value": "Chocolate"
    },
    "requires": {
      "name": "candy"
    }
  }
}

requires

The 'requires' condition requires that the field indicated with the 'name' attribute passes the required validation.


matches

The 'matches' condition requires that the value of the field indicated with the 'name' attribute matches the value that is set in the 'value' attribute.


not_matches

The 'matches' condition requires that the value of the field indicated with the 'name' attribute does not match the value that is set in the 'value' attribute.


Validation


required

fails validation if the field value is empty.

{validate: {required: true}
matches

fails validation if the field value does not match the value of the field indicated.

{validate: {matches: 'password_1'}
valid_email

fails validation if the field value is not a valid email address.

{validate: {valid_email: true}
valid_emails

fails validation if any value in a comma separated list is not a valid email

{validate: {valid_emails: true}
min_length

fails validation if the length of the fields value is shorter then the indicated value

{validate: {min_length: '8'}
max_length

fails validation if the length of the fields value is longer then the indicated value

{validate: {max_length: '10'}
exact_length

fails validation if the length of the fields value is not exactly the same as the indicated value

{validate: {exact_length: '8'}
greater_than

fails validation if the value of the field is less than the indicated value after using parseFloat.

{validate: {greater_than: '16'}
less_than

fails validation if the value of the field is greater than the indicated value after using parseFloat.

{validate: {less_than: '100'}
alpha

fails validation if the value of the field contains anything other than alphabetical characters.

{validate: {alpha: true}
alpha_numeric

fails validation if the value of the field contains anything other than alpha-numeric characters.

{validate: {alpha_numeric: true}
alpha_dash

fails validation if the value of the field contains anything other than alpha-numeric characters, underscores, or dashes.

{validate: {alpha_dash: true}
numeric

fails validation if the value of the field contains anything other than numeric characters.

{validate: {numeric: true}
integer

fails validation if the value of the field contains anything other than an integer.

{validate: {numeric: true}
decimal

fails validation if the value of the field contains anything other than a decimal.

{validate: {decimal: true}
is_natural

fails validation if the value of the field contains anything other than a natural number: 0, 1, 2, 3, etc.

{validate: {is_natural: true}
is_natural_no_zero

fails validation if the value of the field contains anything other than a natural number, but not zero: 1, 2, 3, etc.

{validate: {is_natural_no_zero: true}
valid_ip

fails validation if the value of the field is not a valid IP address.

{validate: {valid_ip: true}
valid_url

fails validation if the value of the field is not a valid url.

{validate: {valid_url: true}
valid_base64

fails validation if the value of the field contains anything other than valid Base64 characters.

{validate: {valid_base64: true}

Themes

Themes help BerryJS to fit seemlessly into your current site.

Bootstrap

The bootstrp theme is the default theme and is the one that is tested most thoroughly. It impliments all of the basic elements and uses the 12 column grid. The pre and post pieces of form groups are also impilmented


Plugins

Plugins are used to extend the functionality of BerryJS as well as to impliment new features that may only make sense for a subset of people.

Modal

This plugin will automatically create a modal popup of a form if the target is not selected or the target element is not found. In practice this would look like this:

var myForm = $().berry(options);
To make use of this plugin the plugin just needs to be included and no target selected.


Backbone

Using this plugin will allow you to bind your model to the form, the fields can be defined on the model as a 'schema' and the model will be updated using model.set on the 'save' event of the form. If you don't want to use all of the fields defined on in the schema just pass an arr with the names of the fields you do want to use, you can also use the array to change the order of the fields as this is taken as priority over the definition. The schema should be defined as an object of the form

bbModel = new Backbone.model.extend({
  "schema": {
    "First Name": {}, //name and label are assumed to be 'first_name' and 'First Name' respectively
    "Home Address": {name: 'address', type: 'address'}
  }

var myForm = $('.myform').berry({model: new bbModel(), fields: ['first_name']});
To use this plugin the plugin just needs to be included and a model passed in to it. A reference to the model is also available at myForm.options.model, this is useful from within an event callback function. Two new events are also used with this plugin:
  • save

    triggered right before the model is updated with the new values

  • saved

    triggered right after the model is updated with the new values


© Adam Smallcomb 2017