Skip to content
This repository has been archived by the owner on Mar 5, 2024. It is now read-only.
François Daoust edited this page Jul 7, 2012 · 49 revisions

This documentation is work in progress and very incomplete for the time being. Please check the JSON Form Reference in the meantime.

Overview

The JSON Form library is a JavaScript client-side library that takes a structured data model defined using JSON Schema as input and returns a Bootstrap-friendly HTML form that matches the schema. The layout of the generated HTML form may be entirely fine-tuned through a simple declarative mechanism.

The generated HTML form includes client-side validation logic and provides direct inline feedback to the user upon form submission (provided a JSON Schema validator is available). If values are valid, the JSON Form library uses the submitted values and the data model to create the appropriate JavaScript data object.

This wiki contains the documentation of the JSON Form Library.

Table of Contents

  1. Getting started
  2. Outline of a JSON Form object
  3. Using JSON Schema to describe your data model
    1. Basic JSON Schema example
    2. Hey, that's not pure JSON Schema!
    3. Supported types
    4. Building more complex structures
    5. Dealing with arrays
  4. Default form layout
    1. From schema element to form field
    2. Common schema properties
    3. Order of the input fields in the form
  5. Controlling the layout of the form
    1. A list of fields
    2. Referencing nested schema properties
    3. Common field properties
      1. Append a message to a field: the append property
      2. Describe a field: the description property
      3. Style fields: the htmlClass property
      4. Skip field's title: the notitle property
      5. Prepend a message to a field: the prepend property
      6. Field's title: the title property
    4. Text input fields
      1. Simple text: the text type
      2. Gathering secrets: the password type
      3. Large text: the textarea type
      4. HTML authoring input: the wysihtml5 type
      5. Code (JavaScript, JSON...): the ace type
      6. Color picker: the color type
    5. Checkbox fields
      1. Boolean flag: the checkbox type
      2. Multiple options: the checkboxes type
    6. Selection fields
      1. Selection list: the select type
      2. A list of radio buttons: the radios type
      3. Image selector: the imageselect type
    7. Groups of fields
      1. Set of fields: the fieldset type
      2. Advanced options section: the advancedfieldset type
      3. Authentication settings section: the authfieldset type
      4. Generic group: the section type
      5. Group of buttons: the actions type
    8. Arrays
      1. Generic array: the array type
      2. Arrays with tabs: the tabarray type
    9. Alternative sections
      1. Alternative: the selectfieldset type
    10. Buttons
      1. Submit the form: the submit type
      2. Action button: the button type
    11. File upload
      1. Upload a file: the file type
      2. Upload a file with transloadit: the file-transloadit type
    12. Miscellaneous fields
      1. Guide users: the help type
      2. Hidden form values: the hidden type
  6. Form submission
    1. Validation
    2. Error reporting
    3. Accessing submitted values
  7. Label/Values templating
    1. The tpldata property
    2. Add array item index with {{idx}}
    3. Use a field's value as tab legend with {{value}} and valueInLegend
    4. Reference the value of another field with {{values.xxx}}
  8. Extending JSON Form
    1. Field's view
    2. Binding to onBeforeRender events
    3. Binding to onInsert events
    4. Binding to onClick events
    5. Binding to onChange events
  9. Using previously submitted values to initialize a form
  10. JSON Form options
  11. Examples
  12. References
  13. Dependencies
  14. License

Getting started

To get started with JSON Form, you need to retrieve a copy of the repository, either cloning the git repository or downloading the repository as a zip file.

Once you have a local copy on your local hard drive, open the example.html file in your favorite Web browser. It contains the following example.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Getting started with JSON Form</title>
    <link rel="stylesheet" style="text/css" href="deps/opt/bootstrap.css" />
  </head>
  <body>
    <h1>Getting started with JSON Form</h1>
    <form></form>
    <div id="res" class="alert"></div>
    <script type="text/javascript" src="deps/jquery.min.js"></script>
    <script type="text/javascript" src="deps/underscore.js"></script>
    <script type="text/javascript" src="deps/opt/jsv.js"></script>
    <script type="text/javascript" src="lib/jsonform.js"></script>
    <script type="text/javascript">
      $('form').jsonForm({
        schema: {
          name: {
            type: 'string',
            title: 'Name',
            required: true
          },
          age: {
            type: 'number',
            title: 'Age'
          }
        },
        onSubmit: function (errors, values) {
          if (errors) {
            $('#res').html('<p>I beg your pardon?</p>');
          }
          else {
            $('#res').html('<p>Hello ' + values.name + '.' +
              (values.age ? '<br/>You are ' + values.age + '.' : '') +
              '</p>');
          }
        }
      });
    </script>
  </body>
</html>

This page creates a form that asks for user's name and age. The user's name is a required field, while the age is optional. The form gets rendered with two input fields and a submit button. The onSubmit function is called upon form submission. If you hit the Submit button without entering values or if the age you entered is not a number, error messages appear next to the input fields.


Back to top

Outline of a JSON Form object

The $.jsonForm function takes a JSON Form object as parameter. The basic outline of a JSON Form object is:

{
  "schema": {
    // Object that describes the data model
  },
  "form": [
    // Array that describes the layout of the form
  ],
  "onSubmitValid": function (values) {
    // Callback function called upon form submission when values are valid
  }
}

The schema property is required. It describes the structured data model that must be created when the form is submitted. It is a JSON object that follows the properties definition of the JSON Schema specification. JSON Schema lets you describe the data structure that you'd like to generate from the form as well as constraints on possible values, such as the maximum number of characters that a string may contain. Check Using JSON Schema to describe your data model below for more info.

The form property is an array that describes the list and order of fields that compose the form. This property is optional. In its absence, a default form is generated from the schema. The structure of a form is not necessarily flat: an item in the form array may describe a group of fields or an array. See Controlling the layout of the form below.

The onSubmitValid callback is optional as well but chances are you will want to do something with the values entered by the user when the form is submitted and that callback is the easiest way around. It receives the object generated from the submitted values and the schema, provided the values are valid. If you need to do something special when submitted values are invalid for some reason, rather use the onSubmit callback, called whenever the form is submitted, that receives the list of errors as first parameter. Check Accessing submitted values below for an overview of the different possibilities.


Back to top

Using JSON Schema to describe your data model

JSON Schema is a JSON based format for defining the structure of JSON data. The RFC specification describes the possible contents of the schema property in the JSON Form object.

Basic JSON Schema example

Here is an example of a simple schema with two string properties: a name property and a gender property. The gender is a string that must match one of "male", "female" or "alien".

{
  "name": {
    "title": "Name",
    "description": "Nickname allowed",
    "type": "string"
  },
  "gender": {
    "title": "Gender",
    "description": "Your gender",
    "type": "string",
    "enum": [
      "male",
      "female",
      "alien"
    ]
  }
}

The JSON Form library uses the data schema to validate submitted values. For instance, the following JSON object is valid against the above schema:

{
  "name": "François Daoust",
  "gender": "male"
}

... whereas the following object is not both because the name is not a string and because the gender is not one of the allowed values:

{
  "name": 42,
  "gender": "machine"
}

More importantly, the JSON Form library uses the data schema to build the corresponding form. For instance, JSON Form would create the following form for this basic example (note the use of a select field for the gender enumeration):

TODO: upload image


Back to top

Hey, that's not pure JSON Schema!

If you've already played with JSON Schema, something may bug you in the above example: it is not fully compliant with JSON Schema. The example should rather be:

{
  "type": "object",
  "properties": {
    "name": {
      "title": "Name",
      "description": "Nickname allowed",
      "type": "string"
    },
    "gender": {
      "title": "Gender",
      "description": "Your gender",
      "type": "string",
      "enum": [
        "male",
        "female",
        "alien"
      ]
    }
  }
}

In other words, the wrapping object is missing:

{
  "type": "object",
  "properties": {
    contents
  }
}

True. Good catch, thanks for noticing... It just happens that, in basically all cases in JSON Form, the first level is going to be an object, so you may simply omit that level and start with the contents part directly. That said, if you prefer to stick to a pure JSON Schema format, you can! In fact, if your contents part defines a property named properties, you must define the wrapping context, otherwise JSON Form won't know that you're talking about a properties property and will rather think that you're talking about an object whose properties are the children of the properties property. See the problem? Don't worry if you don't, simply avoid fields named properties and you'll be safe no matter what.


Back to top

Supported types

JSON Form supports all JSON Schema simple types that make sense in the context of an HTML form:

  • string for strings
  • number for numbers, including floating numbers
  • integer for integers
  • boolean for booleans
  • array for arrays
  • object for objects.

In particular, null is not supported because it does not mean much in an HTML form; any and union types are not supported either because it's hard to come up with a practical input field that can create any type of data.

Types are the most straightforward constraint you can put on property values. All properties must have a type, otherwise JSON Form will go berserk and attempt to destroy the Earth. You may add more constraints using other JSON Schema properties. We've already seen required to enforce the presence of a value and enum as a way to define a list of possible values. You may also use maxLength or pattern for instance to add constraints that match your needs.


Back to top

Building more complex structures

The object type is interesting because it allows to nest objects and build more complex structures. For instance, you may want to separate properties about an author from the rest of the properties to produce the following data structure:

{
  "message": some text,
  "author": {
    "name": name,
    "gender": gender,
    "magic": magic_number
  }
}

The following JSON Schema would do the trick (omitting the wrapping object as usual):

{
  "message": {
    "type": "string",
    "title": "Message"
  },
  "author": {
    "type": "object",
    "title": "Author",
    "properties": {
      "name": {
        "type": "string",
        "title": "Name"
      },
      "gender": {
        "type": "string",
        "title": "Gender",
        "enum": [ "male", "female", "alien" ]
      },
      "magic": {
        "type": "integer",
        "title": "Magic number",
        "default": 42
      }
    }
  }
}

By default, JSON Form groups all the input fields created from the properties of an object together in a fieldset:

TODO: upload image


Back to top

Dealing with arrays

Arrays are a pain to support in a form. By essence, the number of items in an array is up to the user of the form so there needs to be some way to add/remove items. That's just the first step though. You'll quickly want some way to reorder items in an array as well, or to define array items that are more than just a simple input field. Oh, by the way, nesting arrays would be good too, kthxbai.

Well, good news, JSON Form does it all for you! Use the array type in the schema and... that's it! For instance, let's say you would like the user to input a list of friends, in order to generate an array such as:

[
  { "nick": "tidoust", "gender": "male", "age": 34 },
  { "nick": "titine", "gender": "female", "age": 6 },
  { "nick": "E.T.", "gender": "alien" }
]

Here is the schema that you would use:

{
  "friends": {
    "type": "array",
    "items": {
      "type": "object",
      "title": "Friend",
      "properties": {
        "nick": {
          "type": "string",
          "title": "Nickname",
          "required": true
        },
        "gender": {
          "type": "string",
          "title": "Gender",
          "enum": [ "male", "female", "alien" ]
        },
        "age": {
          "type": "integer",
          "title": "Age"
        }
      }
    }
  }
}

And here is a screenshot of the form generated by JSON Form. You can add/remove items using the corresponding buttons at the end of the array. You can also reorder items using drag-and-drop.

TODO: upload screenshot

NB: reordering items is only available when the jQuery.ui.sortable plug-in is up and running. To set it up, just add the following lines to your HTML page to complete the list of scripts:

<script type="text/javascript" src="deps/opt/jquery.ui.core.js"></script>
<script type="text/javascript" src="deps/opt/jquery.ui.widget.js"></script>
<script type="text/javascript" src="deps/opt/jquery.ui.mouse.js"></script>
<script type="text/javascript" src="deps/opt/jquery.ui.sortable.js"></script>

There is one important restriction to keep in mind: while JSON Schema allows to define arrays whose items follow different schemas depending on their position in the array, JSON Form only supports arrays whose items are all identical. In other words, the items property of an array property in the schema definition must be an object. For example, while a valid JSON Schema, the following schema is not allowed in JSON Form:

{
  "boo": {
    "type": "array",
    "items": [
      { "type": "string" },
      { "type": "number" }
    ]
  }
}

Back to top

Default form layout

From schema element to form field

To generate the form, the JSON Form library parses the schema recursively and checks the type and options of the properties it defines to decide upon the type of HTML form input to append to the form. The following mapping is used:

  • A string property that defines a list of possible values in an enum property generates a selection field, i.e. a <select> element
  • A string property that defines a format property whose value is color generates a color picker field
  • A generic string property generates a text input otherwise, i.e. an <input type="text"> element.
  • A number property generates a text input, i.e. an <input type="text"> element.
  • An integer property generates a text input as well, i.e. an <input type="text"> element.
  • A boolean property generates a checkbox, i.e. an <input type="checkbox"> element.
  • An object property generates a fieldset, i.e. a <fieldset> element. The fieldset contains the sub-form generated by the object's properties.
  • An array property generates an array wrapper that features Add/Remove buttons and items reordering. Each array item is generated from the sub-form defined in the items property of the array (which must be an object and not an array as mentioned in the previous section). The array is initially rendered with one item. That item cannot be removed (note the user may decide to leave that item empty though, meaning the submitted array may well be empty).

Back to top

Common schema properties

The JSON Form library uses the information available in the JSON schema to complete each generated field. In particular:

  • The title property serves as label for the input.
  • The description property is displayed next to the input field to guide user input.
  • The default property sets the initial value of a field.

Other schema properties are typically used for validation purpose (the required property for instance). The mapping and markup generated may evolve in the future, in particular to take advantage of the new form input types introduced in HTML5 when most browsers support them.

JSON Form automatically generates an ID for all input fields. IDs are prefixed by jsonform_ and a form counter to avoid conflicts (and allow JSON Form to be used more than once at the same time in a given page). Check the JSON Form options section if you need to override the default prefix for some reason.

JSON Form also sets the name attribute of all input fields to the id of the schema property that gave birth to it (the id is basically the path that leads to the property in the schema).


Back to top

Order of the input fields in the form

JSON Form follows the order of the JSON Schema's object properties as they appear to the code when it loops over the object using a for ... in loop. Now, even though it seems natural to read an object's definition from top to bottom, there is simply no guarantee that an object's properties will come out in any particular order when JSON Form parses the JSON Schema's object. It just happens that, most of the time, the order in which the properties appear to the code are the same as the natural top-to-bottom order... but that's only most of the time!

In other words, even it seems to work as you might expect, you should not assume that the fields of the generated form will follow the order of the properties in the JSON Schema's object. Is it problematic? It could very well be! Fortunately, JSON Form lets you take control of the layout of the form, let's see how...


Back to top

Controlling the layout of the form

So far, we've seen how JSON Form turns a JSON schema into an HTML form all on its own. That's great but... the truth is, as soon as you start using JSON Form, you'll come up with new use cases that are not covered by default such as:

  • It you ask for a password, you may want to generate a password input.
  • You may want to add a Cancel button, or a snippet of HTML in between two input fields
  • You may want to provide your own validation error messages.
  • You may want to provide alternative sub-forms based on some initial choice.
  • You may want to hide some input fields in an Advanced options section.
  • You may want to display a textarea for a string property, or radio buttons for a selection field
  • You may want to use a super dooper image selector when the field lets the user choose between icons
  • You may want to ensure that fields appear in a precise order
  • and so on...

In other words, JSON Form's default behavior is all very nice, but it's not quite enough. Power to the people! Great, let's do that... Controlling the layout of the form is precisely the raison d'être of the form section in the JSON Form object:

{
  "schema": {
    // Data model
  },
  "form": [
    // This is where you can control the layout of the form!
  ]
}

Note the split between the data model and the layout. That's on purpose!

A list of fields

The form section describes the list of fields that compose the HTML form. It is a JSON array. Each item in the list describes a section of the resulting form. The order of the sections in the generated HTML form follows the order of the items in the array.

An array item may be:

  • A string with the specific value "*". When JSON Form encounters that value, it generates a form with one field per property defined in the schema, using the default form layout. Use this specific value for simple forms when you simply want to override the remaining form elements (the Submit button in particular). Keep in mind that the order of the fields in the generated form is likely going to be the one of the properties in the JSON Schema but that this is not guaranteed. Here is an example of a simple form that uses *:
[
  "*",
  {
    "type": "submit",
    "title": "Eat this!"
  }
]
  • A string that references the name of a property in the schema. The JSON Form library generates the default field that matches the property. Use this method when you do not need to override the generated field by itself, but simply its position within the resulting form. If you wonder how you may reference properties that are at a nested level (when the schema includes object properties), hold on, we'll cover that in a minute. An example that would work for the Basic JSON Schema example:
[
  "name",
  {
    "type": "help",
    "helpvalue": "The rest of the form is entirely optional, feel free to ignore."
  },
  "gender",
  {
    "type": "submit",
    "title": "Roger"
  }
]
  • A JSON object whose key property references the name of a property in the schema. The object may also override some of the properties of the schema property and/or define additional properties to control how JSON Form generates the resulting field. Use this method to change the visual aspect of an input field. For instance, to replace the text input by a textarea in the first example:
[
  {
    "key": "name",
    "type": "textarea"
  },
  "gender",
  {
    "type": "submit",
    "title": "Roger"
  }
]

In case you're wondering, using "gender" to reference the schema is strictly equivalent to using { "key": "gender" }, only a bit shorter and more convenient to write.

  • A JSON object not linked to any property in the schema. Use this method to produce additional sections in the form, such as fieldsets, helper text, or expandable sections. We've already seen examples en passant with the help and submit element types. You could also wrap optional fields in an Optional fieldset:
[
  "name",
  {
    "type": "fieldset",
    "title": "Optional",
    "items": [
      "gender"
    ]
  },
  {
    "type": "submit",
    "title": "Roger"
  }
]

When you don't define a form section, JSON Form creates a default one for you and generates the corresponding form:

[
  "*",
  {
    "type": "actions",
    "items": [
      {
        "type": "submit",
        "title": "Submit"
      }
    ]
  }
]

In other words, it produces a form that contains all properties defined in the schema (represented by the \* value) followed by an actions fieldset that contains a submit button.


Back to top

Referencing nested schema properties

The examples of the previous section stuck to flat schemas, i.e. schemas that do not contain object or array properties. Adding these possibilities back in the mix produces nested properties. Property names that appear at a deeper level may not be globally unique across the schema so you cannot simply reference them by name. To reference a property that is listed in the properties section of an object element, simply use a dotted notation to describe the path that leads to the property in the schema. For instance, consider the following schema:

{
  "author": {
    "type": "object",
    "properties": {
      "name": {
        "type": "object",
        "properties": {
          "firstname": { "type": "string", "title": "First name" },
          "lastname": { "type": "string", "title": "Last name" }
        }
      }
    }
  }
}

To reference the firstname property from an element in the form section, use "author.name.firstname", as in:

[
  "author.name.firstname",
  "author.name.lastname"
]

Similarly, to reference a property that is listed in the items section of an array element, simply use square brackets next to the array property name combined with the previous dotted notation. For instance, completing a bit the previous schema to turn it into an array of authors:

{
  "authors": {
    "type": "array",
    "items": {
      "type": "object",
      "properties": {
        "name": {
          "type": "object",
          "properties": {
            "firstname": { "type": "string", "title": "First name" },
            "lastname": { "type": "string", "title": "Last name" }
          }
        }
      }
    }
  }
}

To reference the firstname property from an element in the form section, use "authors[].name.firstname" as in:

[
  {
    "type": "array",
    "items": {
      "authors[].name.firstname",
      "authors[].name.lastname"
    }
  }
]

Beware: It is relatively easy to create an invalid form when the schema contains arrays. You can only reference array items from an element in the form section that is itself part of an array. Said differently, the array depth of an element in the form section must match that of the element it references in the schema. The following form section is not valid because the form element is not part of an array but still references an array item:

[
  "authors[].name.firstname",
  "authors[].name.lastname"
]

Back to top

Common field properties

Most fields (except groups of fields) react to a few common properties that fine-tune the look-and-feel of the field generated by JSON Form. These properties are described below in alphabetic order, and illustrated with this short example:

{
  "schema": {
    "mood": {
      "type": "string",
      "title": "Mood of the day",
      "description": "Describe how you feel with a short adjective",
      "default": "happy"
    }
  },
  "form": [
    {
      "key": "mood",
      "prepend": "I feel",
      "append": "today"
      "notitle": true,
      "htmlClass": "usermood"
    }
  ]
}

append

Use this property to insert a suffix after the generated form input. The property accepts an HTML fragment string as value. Note that the suffix is not appended to the final value when the form is submitted.

See also prepend

Describe a field: the description property

By default, JSON Form displays the description property defined in the schema next to the input field to guide user input. Set this property in the form section to override that of the schema element (or to define it if the schema does not).

Style fields: the htmlClass property

Use this property to define additional classes for the generated field. Classes must be separated by whitespaces. Note classes are set to the <div> element that wraps the input field, not to the input field itself.

Skip field's title: the notitle property

Sometimes, you may want JSON Form not to insert a label for the input field. Use this property to ignore the title property of the schema element.

Prepend a message to a field: the prepend property

Use this property to insert a prefix before the generated form input. The property accepts an HTML fragment string as value. Note that the prefix will not appear in the final value when the form is submitted.

See also append

Field's title: the title property

By default, JSON Form uses the title property defined in the schema as label for the generated input field. Set this property in the form section to override that of the schema element (or to define it if the schema does not).


Back to top

Now that you know how to author the form section, reference properties in the underlying schema and fine-tune a few common properties, let's see how we can go a step further and actually change the type of field that gets generates. JSON Form includes about 25 different fields, ranging from the usual text input field to tabs and wysiwyg HTML editors. That list will grow over time ; if you cannot find the field you're looking for in the list below, no big deal, check the Extending JSON Form section and create your own!

Text input fields

Text input fields are linked to string properties in the schema. They may be used to gather anything from a word to a large HTML snippet.

Check Selection fields if the string property defines an enum property.

Simple text: the text type

JSON Form generates a text field by default for all schema properties of type string (save enumerations and colors). Not much to say about it, that's just a regular <input type="text"> input field!


Back to top

Gathering secrets: the password type

If you need to gather a password, simply set the type of the form field's type to password to have JSON Form generate an <input type="password"> input field.

{
  "schema": {
    "pwd": {
      "type": "string",
      "title": "Your secret"
    }
  },
  "form": [
    {
      "key": "pwd",
      "type": "password"
    }
  ]
}

Back to top

Large text: the textarea type

The name says it all. Use textarea to generate a <textarea> field.

{
  "schema": {
    "comment": {
      "type": "string",
      "title": "Your thoughts"
    }
  },
  "form": [
    {
      "key": "comment",
      "type": "textarea"
    }
  ]
}

Back to top

HTML authoring input: the wysihtml5 type

Code (JavaScript, JSON...): the ace type

Color picker: the color type

JSON Form generates a color input field by default for all schema properties of type string that also have a format property set to color.

{
  "schema": {
    "maincolor": {
      "type": "string",
      "title": "Main color",
      "format": "color"
    }
  }
}

Internally, JSON Form uses the Spectrum library to create the color picker, so make sure that you include the spectrum.js and spectrum.css libraries before using this type of field.


Back to top

Checkbox fields

Checkbox fields are linked to boolean properties in the schema. They may also be linked to array properties whose items schema defines a list of possible values in an enum property.

Boolean flag: the checkbox type

JSON Form generates a checkbox field by default for all schema properties of type boolean. The default checkbox is kind of dull because it really displays a little checkbox. You'll probably want some way to define an inline message next to the checkbox for the user. Good news, that's precisely the purpose of the inlinetitle property.

{
  "schema": {
    "flag": {
      "type": "boolean",
      "title": "Adult"
    }
  },
  "form": [
    {
      "key": "flag",
      "inlinetitle": "Check this box if you are over 18"
    }
  ]
}

Back to top

Multiple options: the checkboxes type

If you need the user to select one or more options among a list of choices, the checkboxes form field is for your. It applies to an array property whose items schema explicitly defines a list of possible values in an enum property.

If you want to replace the values that appear in the schema by more user-friendly values, simply define the mapping between the values and the option's label in a titleMap as in the following example.

{
  "schema": {
    "menu": {
      "type": "array",
      "title": "Options",
      "items": {
        "type": "string",
        "title": "Option",
        "enum": [
          "starter",
          "maincourse",
          "cheese",
          "dessert"
        ]
      }
    }
  },
  "form": [
    {
      "key": "menu",
      "type": "checkboxes",
      "titleMap": {
        "starter": "Starter would be great",
        "maincourse": "No way I'll skip the main course",
        "cheese": "Cheddar rules!",
        "dessert": "Thumbs up for a dessert"
      }
    }
  ]
}

Back to top

Selection fields

Selection fields are linked to string properties in the schema that define an enum property with an enumeration of possible values. Such fields allow the selection of one or more options depending on the type of field.

The enumeration defined in the schema sets the list of values that your application will receive once the form is submitted. If you want to replace these values in the form by more user-friendly messages, define the mapping in the titleMap property.

{
  "schema": {
    "gender": {
      "type": "string",
      "title": "Gender",
      "enum": [ "male", "female", "alien" ]
    }
  },
  "form": [
    {
      "key": "gender",
      "titleMap": {
        "male": "Dude",
        "female": "Dudette",
        "alien": "I'm from outer space!"
      }
    }
  ]
}

Selection list: the select type

JSON Form generates a select field by default for all schema properties of type string that define an enumeration list. See above for a typical example.


Back to top

A list of radio buttons: the radios type

If you'd rather see the list of options rendered as radio buttons, use the radios type.

{
  "schema": {
    "language": {
      "type": "string",
      "title": "Best language",
      "enum": [ "JavaScript", "Python", "PHP", "Java", "C++", "other" ]
    }
  },
  "form": [
    {
      "key": "language",
      "type": "radios"
    }
  ]
}

Back to top

Image selector: the imageselect type

The image selector lets the user pick up an image in a list. Internally, the image selector produces a string as any other selection field. It converts the string into actual images when the form is rendered. The image selector is mostly intended for icons and small images for the time being.

{
  "schema": {
    "icon": {
      "title": "Choose an icon",
      "type": "string",
      "enum": [
        "address-book",
        "archive",
        "balloon",
        "calendar",
        "camera",
        "cd",
        "disk",
        "heart",
        "home",
        "mail"
      ]
    }
  },
  "form": [
    {
      "key": "icon",
      "type": "imageselect",
      "imageWidth": 64,
      "imageHeight": 64,
      "imageButtonClass": "btn-inverse",
      "imagePrefix": "http://icons.iconarchive.com/icons/double-j-design/origami-colored-pencil/64/blue-",
      "imageSuffix": "-icon.png",
      "imageSelectorColumns": 4,
      "imageSelectorTitle": "Random choice"
    }
  ]
}

From the example, you can tell that there are a number of properties you may want to provide to control the rendering of the image selector:

  • imageWidth lets you specify the width of the images to render. It is optional and defaults to 32.
  • imageHeight lets you specify the height of the images to render. It is optional and defaults to 32.
  • imageButtonClass lets you set a class to the button that wraps each image in the image select. For instance, setting the class to btn-inverse with Bootstrap would render the image on a dark background. The propery is optional.
  • imagePrefix and imageSuffix are used to create the final URL of images. In turn, this lets you stick to simple strings in the enumeration that defines the possible images. The final image URL is imagePrefix + (option value) + imageSuffix. Both properties are optional and default to an empty string.
  • imageSelectorColumns lets you set the maximum number of images to display per row in the image selector. The property is optional and defaults to 5. JSON Form balances the number of items per row and the number of items in the last row. It may render fewer items per row as a result.
  • imageSelectorTitle is the label of the button that gets displayed when no image has been selected yet. It is optional and defaults to the string Select....

Back to top

Groups of fields

It is often convenient to group a set of fields together in a form to ease readability and thus improve the user experience. JSON Form provides a few types for that purpose.

Set of fields: the fieldset type

JSON Form generates a fieldset for all schema properties of type object, but you may also want to generate a fieldset without referencing a schema property at all. As you might expect from the name, a fieldset field simply produces a <fieldset> element in the resulting form.

When set, the expandable boolean property tells JSON Form to render the fieldset's title and only expand the fieldset's section when the user clicks on it. This is typically useful for advanced options that users could skip on first read.

If you're using Bootstrap to style the resulting form, please note that it does not include styles for expandable sections at first. You might want to add a few extra stylesheet properties to your CSS to add a visual hint that the section can be expanded/collapsed, for instance:

.expandable > legend:before {
  content: '\25B8';
  padding-right: 5px;
}
.expanded > legend:before {
  content: '\25BE';
}
{
  "schema": {
    "comment": {
      "type": "string",
      "title": "Comment"
    },
    "name": {
      "type": "string",
      "title": "Name"
    },
    "age": {
      "type": "number",
      "title": "Age"
    }
  },
  "form": [
    {
      "key": "comment",
      "type": "textarea"
    },
    {
      "type": "fieldset",
      "title": "Author",
      "expandable": true,
      "items": [
        "name",
        "age"
      ]
    }
  ]
}

Back to top

Advanced options section: the advancedfieldset type

The advancedfieldset type is a shortcut type. It is the same thing as an expandable fieldset whose title is Advanced settings.

{
  "schema": {
    "name": {
      "type": "string",
      "title": "Name"
    },
    "age": {
      "type": "number",
      "title": "Age"
    }
  },
  "form": [
    "name",
    {
      "type": "advancedfieldset",
      "items": [
        "age"
      ]
    }
  ]
}

Back to top

Authentication settings section: the authfieldset type

The authfieldset type is a shortcut type. It is the same thing as an expandable fieldset whose title is Authentication settings.

{
  "schema": {
    "name": {
      "type": "string",
      "title": "Name"
    },
    "key": {
      "type": "string",
      "title": "Access key"
    }
  },
  "form": [
    "name",
    {
      "type": "authfieldset",
      "items": [
        "key"
      ]
    }
  ]
}

Back to top

Generic group: the section type

From time to time, you'll want to group fields without generating a proper <fieldset>. This might be for styling purpose, or as a convenient way to define a tab in a tabarray. The generic section type generates a group of fields without title wrapped in a <div> element.

{
  "schema": {
    "comment": {
      "type": "string",
      "title": "Comment"
    },
    "name": {
      "type": "string",
      "title": "Name"
    },
    "age": {
      "type": "number",
      "title": "Age"
    }
  },
  "form": [
    {
      "key": "comment",
      "type": "textarea"
    },
    {
      "type": "section",
      "title": "Author",
      "items": [
        "name",
        "age"
      ]
    }
  ]
}

Back to top

Group of buttons: the actions type

To highlight the section that contains form buttons, use the actions type to wrap button fields in a <div class="form-actions"> container.

{
  "schema": {
    "search": {
      "type": "string",
      "title": "Search"
    }
  },
  "form": [
    "search",
    {
      "type": "actions",
      "items": [
        {
          "type": "submit",
          "title": "Submit"
        },
        {
          "type": "button",
          "title": "Cancel"
        }
      ]
    }
  ]
}

Back to top

Arrays

Arrays introduce a new level of interaction with the user, because the number of items in an array is not know a priori, meaning that the user may manage array items while filling out the form. Array items may be arbitrarily complex, which means that adding an array item could very well produce a series of 10 additional input fields, including groups of fields and nested arrays.

Array items are not necessarily bound to one and only one schema array element. They may actually reference array items that are different positions in the schema. This is great because the data model that suits your code may not match the way you might want users to think about that data. It comes with a price, though: if you don't pay attention, it is relatively easy to generate invalid form sections, all the more so if you want to play with nested arrays. In particular, beware of references to schema elements from the form section.

The rule of thumb is: the number of [] in references to schema elements must match the depth of the array in the form section.

That rule is illustrated in the example below:

{
  "schema": {
    "friends": {
      "type": "array",
      "items": {
        "type": "object",
        "title": "Friend",
        "properties": {
          "nick": {
            "type": "string",
            "title": "Nickname"
          },
          "animals": {
            "type": "array",
            "items": {
              "type": "string",
              "title": "Animal name"
            }
          }
        }
      }
    }
  },
  "form": [
    {
      "type": "array",
      "items": [
        "friends[].nick",
        {
          "type": "array",
          "items": [
            "friends[].animals[]"
          ]
        }
      ]
    }
  ]
}

Generic array: the array type

JSON Form generates an array by default for all properties of type array in the JSON Schema. For each array item, JSON Form generates the default form that follows the items property of the array in the JSON Schema.

The above could simply be written as:

{
  "schema": {...},
  "form": [
    "friends"
  ]
}

There is a slight nuance between that definition and the previous one, though. Keep in mind that the order of the fields in the generated form is not guaranteed if you're not explicit about it: the animals subarray could potentially appear before nick here.

JSON Form creates a first array item in the generated form that cannot be removed. JSON Form then adds the necessary logic to add/remove array items, as well as to reorder items in the array. Reordering items works through drag-and-drop and is only available when the jQuery UI Sortable library is loaded.


Back to top

Arrays with tabs: the tabarray type

Users will quickly get lost with classic arrays when the number of fields per array item increases. When that happens, switching to a tabarray helps roll back to a more manageable situation where the list of array items appears as a list of tabs on the left and where only the details of the selected tab are visible on the right.

Switching to a tabarray type of diel is as easy as using the value tabarray instead of array in the form section of the JSON Form object.

{
  "schema": {...},
  "form": [
    {
      "type": "tabarray",
      "items": [
        "friends[].nick",
        {
          "type": "array",
          "items": [
            "friends[].animals[]"
          ]
        }
      ]
    }
  ]
}

Visually, the list of tabs on the left is the only thing that the users gets to see at all times. By default, JSON Form labels tabs Item xx (where xx gets replaced by the index of the tab, starting at 1). That's a good start but you'll probably want more control over the label of the tab so that these values make sense for users. This is where templating comes into play. Internally, JSON Form uses the value of the legend property of the potential container that wraps the children of the tabarray as tab title. Through templating, you can adjust that value to suit your needs. For instance, Item xx would be represented as Item {{idx}}.

On top of the tab index, you can use the value of one of the children as legend for the tab using the {{value}} template variable. That variable gets replaced by the value of the first field in the children of the array that sets a valueInLegend property. This is illustrated in the following example.

{
  "schema": {
    "thoughts": {
      "type": "array",
      "items": {
        "type": "string",
        "title": "Thought",
        "default": "wtf"
      }
    }
  },
  "form": [
    {
      "type": "tabarray",
      "items": [
        {
          "type": "section",
          "legend": "{{idx}}. {{value}}",
          "items": [
            {
              "key": "thoughts[]",
              "valueInLegend": true
            }
          ]
        }
      ]
    }
  ]
}

Back to top

Alternative sections

A form may contain fields that only make sense when the user has made a certain choice. For instance, you may want to let the user choose between a search by text and a search by category, and adjust fields accordingly based on this choice. This is exactly what alternative sections are for.

Alternative: the selectfieldset type

When it encounters a selectefieldset, JSON Form creates a select field whose options are the legend properties of the field's children. It renders the children associated with the selected option.

{
  "schema": {
    "text": {
      "type": "string",
      "title": "Text"
    },
    "category": {
      "type": "string",
      "title": "Category",
      "enum": [
        "Geography",
        "Entertainment",
        "History",
        "Arts",
        "Science",
        "Sports"
      ]
    }
  },
  "form": [
    {
      "type": "selectfieldset",
      "title": "Make a choice",
      "items": [
        {
          "key": "text",
          "legend": "Search by text"
        },
        {
          "key": "category",
          "legend": "Search by category"
        }
      ]
    }
  ]
}

If you need to render more than one field per choice, simply wrap the definition of the choice in a section fieldset whose items are the fields to render.

Note that alternative sections are a purely visual effect. In particular, the choice is not defined in the schema and thus not passed around when the form is submitted. This may change in a future version of JSON Form.


Back to top

Buttons

No buttons, no submission, so you'd better include at least a submit button in the form section of the JSON Form object.

Submit the form: the submit type

The submit field produces a button that submits the form when clicked.

{
  "schema": {...},
  "form": [
    "*",
    {
      "type": "submit",
      "title": "OK Go - This Too Shall Pass"
    }    
  ]
}

The generated button has the call btn-primary which makes the button blue by default if you're using Bootstrap styles.

Action button: the button type

For other buttons, use the button type. Note that generic buttons do not trigger any action when clicked unless you set some event handler. See Binding to onClick events for more info.


Back to top

File upload

Upload a file: the file type

Upload a file with transloadit: the file-transloadit type


Back to top

Miscellaneous fields

JSON Form includes a couple of fields that do not quite fall in any category.

Guide users: the help type

The help field lets you write down some message to guide the user in between two fields. The message to display needs to be specified in a helpvalue property. HTML tags are interpreted.

{
  "schema": {...},
  "form": [
    "*",
    {
      "type": "help",
      "helpvalue": "<strong>Click on <em>Submit</em></strong> when you're done"
    },
    {
      "type": "submit",
      "title": "Submit"
    }
  ]
}

Hidden form values: the hidden type

The hidden field lets you pass some value to the submitted object without displaying that value to the user.

{
  "schema": {
    "apikey": {
      "type": "string",
      "title": "API key",
      "default": "supercalifragilisticexpialidocious"
    },
    "text": {
      "type": "string",
      "title": "Search string"
    }
  },
  "form": [
    {
      "key": "apikey",
      "type": "hidden"
    },
    "text",
    {
      "type": "submit",
      "title": "Search"
    }
  ]
}

Back to top

Form submission

The form gets submitted when the user clicks the submit button (so don't forget to include one... see Submit the form: the submit type). Upon submission, JSON Form:

  1. retrieves all fields values
  2. creates the result object from submitted values based on the schema
  3. runs the validator if it is available to check constraints
  4. highlights potential errors in the form next to the problematic fields
  5. reports potential errors and/or passes the result object to the caller

Steps 3 and 4 are optional.

Validation

Validation of the values entered by the user relies on the JSON Schema Validator library which must be loaded if validation is to be enabled.

Validation is enabled by default. To disable validation, set the validate property of the JSON Form object to false, as in:

{
  "schema": {...},
  "form": [...],
  "validate": false
}

The JSON Schema Validator checks all the constraints expressed in the schema (data type, format, maximum length, number of items...) and reports errors accordingly in an array. Each error basically looks like:

{
  "uri": "urn:uuid:1a52a47d-4c69-4d56-94af-4a8afeabaf73#/text",
  "schemaUri": "urn:uuid:50fae450-67b1-499a-89d8-9d5d2c2d3522#/properties/text",
  "attribute": "maxLength",
  "message": "String is greater than the required maximum length",
  "details": 2
}

Unless you want to override the default error reporting mechanism, you should not really need to care about the meaning of the above error properties. Refer to the JSON Schema Validator documentation if you need more details.

Error reporting

JSON Form highlights errors automatically next to problematic fields, with an error message that tells user why the entered values are wrong.

If you want to override the default behavior, append a displayErrors function to the JSON Form object. This may be useful to translate error messages (errors reported by the validator are in English) or to clarify cryptic ones.

var formObject = {
  "schema": {...},
  "form": [...],
  "displayErrors": function (errors, formElt) {
    for (var i=0; i<errors.length; i++) {
      errors[i].message = "Avast! Ye best be fixin' that field!";
    }
    formElt.jsonFormErrors(errors, formObject);
  }
};

Accessing submitted values

JSON Form calls the onSubmitValid callback function with the result object generated from the submitted values when the form is submitted and when the validation did not report any error.

var formObject = {
  "schema": {...},
  "form": [...],
  "onSubmitValid": function (values) {
    // "values" follows the schema, yeepee!
    console.log(values);
  }
};

If you would like to report a global error message to the user when submitted values are incorrect, use the onSubmit function that gets called no matter what once the validation is over.

var formObject = {
  "schema": {...},
  "form": [...],
  "onSubmit": function (errors, values) {
    if (errors) {
      alert('Check the form for invalid values!');
      return;
    }
    // "values" follows the schema, yeepee!
    console.log(values);
  }
};

Back to top

Using previously submitted values to initialize a form

Gathering user input is great but that's seldom something you'll do once and for all. Whether it is to fix some value, adjust settings or simply because you can, you'll most probably want to allow your users to get back to a form that they previously submitted and change some values.

In order to enable that possibility, there needs to be some way to initialize a form with previously submitted values. There's a JSON Form property for that, it's called value. Simply set that property to the object generated when the form was previously submitted, and JSON Form will initialize the form accordingly.

Taking back the friends example, here is how you could pass on the list of friends that JSON Form might have generated when the form was submitted:

{
  "schema": {
    "friends": {
      // See "Dealing with arrays"
    }
  },
  "value": {
    "friends": [
      { "nick": "tidoust", "gender": "male", "age": 34 },
      { "nick": "titine", "gender": "female", "age": 6 },
      { "nick": "E.T.", "gender": "alien" }
    ]
  }
}

Back to top

Label/Values templating

Templating lets JSON Form expand tags in a template string before rendering using variables that are evaluated at runtime. If you've already read the tab array section of this document, you've already encountered two useful template variables: {{idx}} and {{value}}. JSON Form also features a more generic form that lets you provide the mapping between variables and their values in the tpldata property of the JSON Form object.

The templating system follows the Mustache syntax (although note it only accepts variables). Templating strings can be used in all string properties that will be rendered in the form, namely title, description, legend,append, prepend, inlinetitle, default, helpvalue, value as well as titleMap for enumerations.

Add array item index with {{idx}}

In arrays, {{idx}} gets replaced by the index of the array item, starting at 1.

{
  "schema": {
    "thoughts": {
      "type": "array",
      "items": {
        "title": "A thought",
        "type": "string"
      }
    }
  },
  "form": [
    {
      "type": "array",
      "items": [{
        "key": "thoughts[]",
        "title": "Thought number {{idx}}"
      }]
    }
  ]
}

First array field gets labeled Thought number 1 in the previous example, then Thought number 2 and so on.

Use a field's value as tab legend with {{value}} and valueInLegend

The tab array section already covers the ins and outs of the {{value}} property. It is restricted to direct children of tabarray fields for the time being. It gets replaced by the value of the first field that sets the valueInLegend flag in the descendants of the tabarray field (children, great-children, etc.). This is extremely useful to put a meaningful tab legend.

{
  "schema": {
    "thoughts": {
      "type": "array",
      "title": "Thoughts",
      "items": {
        "type": "string",
        "title": "A thought"
      }
    }
  },
  "form": [
    {
      "type": "tabarray",
      "items": [
        {
          "type": "fieldset",
          "legend": "{{idx}}. {{value}}",
          "items": [
            {
              "key": "thoughts[]",
              "title": "Thought {{idx}}",
              "valueInLegend": true
            }
          ]
        }
      ]
    }
  ]
}

Reference the value of another field with {{values.xxx}}

The tpldata property

The tpldata property of the JSON Form object lets you specify the mapping between variables and values for the templating system. In turn, it makes it possible to have form definitions such as:

{
  "schema": {
    "age": {
      "type": "integer",
      "title": "Age"
    }
  },
  "form": [
    {
      "key": "age",
      "title": "{{user.name}'s age"
    }
  ],
  "tpldata": {
    "user": { "name": "tidoust" }
  }
}

JSON Form applies the data in tpldata to the values defined in the schema and form sections before rendering. In the above example, the title of the resulting age field would be tidoust's age.

When is templating useful? Templating is not that useful when you control the JSON Form object from A to Z. You could typically already do the string replacement yourself, which would have the huge benefit to keep the JSON Form object relatively simple... Just do it if you can! Templating is essentially useful when you'd like to use the same JSON Form object (save its "tpldata" property) in different contexts, e.g. for customization purpose or for different locales.


Back to top

Extending JSON Form

Field's view

Binding to onBeforeRender events

Binding to onInsert events

Binding to onClick events

Binding to onChange events


Back to top

JSON Form options


Back to top

Examples

References

Dependencies

At a minimum, the JSON Form library depends on:

The JSON Form library may require further libraries, depending on the features you need for the forms you need to render. In particular:

  • Bootstrap v2.0.3 or above is more or less needed (unless you enjoy ugly forms, that is) if you don't provide your own styles. JSON Form only needs the bootstrap.css file.
  • The JSON Schema Validator is used to detect and report validation errors upon form submission. The deps/opt folder contains a "build" of the JSON Schema Validator for use in JSON Form.
  • Bootstrap Dropdowns v2.0.3 or above is needed for imageselect fields.
  • jQuery UI Sortable v1.8.20 or above is required for drag-and-drop support within arrays and tabarrays. Note the plugin itself depends on jQuery IU Core, jQuery UI Mouse, and jQuery UI Widget.
  • wysihtml5 is required if the form uses wysihtml5 textarea fields.
  • Spectrum is required if the form uses color fields.

All of these libraries are in the deps folder, although you might want to check their respective Web site for more recent versions.

NB: JSON Form also uses JSON.parse and JSON.stringify which is normally already natively supported by all modern browsers. You may use a JSON library otherwise.

License

The JSON Form library is available under the MIT license.

All the libraries that JSON Form may depend on are licensed under the MIT license, except for the JSON Schema Validator, licensed under the BSD 3 Clause license.


Back to top

Clone this wiki locally