<commit_before>Documentation
=============

1. [Basic Usage](#basic-usage)
1. [Handling Submit](#handling-submit)
1. [Global Options](#global-options)
1. [Form types](#form-types)
1. [Default form types](#default-form-types)
1. [Form definitions](#form-definitions)
1. [Overriding field types and order](#overriding-field-types-and-order)
1. [Standard Options](#standard-options)
    1. [onChange](#onchange)
    1. [Validation Messages](#validation-messages)
    1. [Inline feedback icons](#inline-feedback-icons)
    1. [ngModelOptions](#ngmodeloptions)
1. [Specific options and types](#specific-options-and-types)
    1. [fieldset and section](#fieldset-and-section)
    1. [conditional](#conditional)
    1. [select and checkboxes](#select-and-checkboxes)
    1. [actions](#actions)
    1. [button](#button)
    1. [radios and radiobuttons](#radios-and-radiobuttons)
    1. [help](#help)
    1. [tabs](#tabs)
    1. [array](#array)
    1. [tabarray](#tabarray)
1. [Post process function](#post-process-function)
1. [Events](#events)
1. [Manual field insertion](#manual-field-insertion)
1. [Extending Schema Form](extending.md)

Basic Usage
-----------

First, expose your schema, form, and model to the $scope.
Don't forget to load the ``schemaForm` module.

```javascript
angular.module('myModule', ['schemaForm'])
       .controller('FormController', function($scope) {
  $scope.schema = {
    type: "object",
    properties: {
      name: { type: "string", minLength: 2, title: "Name", description: "Name or alias" },
      title: {
        type: "string",
        enum: ['dr','jr','sir','mrs','mr','NaN','dj']
      }
    }
  };

  $scope.form = [
    "*",
    {
      type: "submit",
      title: "Save"
    }
  ];

  $scope.model = {};
}
```

Then load them into Schema Form using the `sfSchema`, `sfForm`, and `sfModel` directives.

```html
<div ng-controller="FormController">
    <form sf-schema="schema" sf-form="form" sf-model="model"></form>
</div>
```

The `sfSchema` directive doesn't need to be on a form tag, in fact it can be quite useful
to set it on a div or some such inside the form instead. Especially if you like to prefix or suffix the
form with buttons or fields that are hard coded.

Example with custom submit buttons:
```html
<div ng-controller="FormController">
  <form>
    <p>bla bla bla</p>
    <div sf-schema="schema" sf-form="form" sf-model="model"></div>
    <input type="submit" value="Submit">
    <button type="button" ng-click="goBack()">Cancel</button>
  </form>
</div>
```

Handling Submit
---------------
Schema Form does not care what you do with your data, to handle form submit
the recomended way is to use the `ng-submit` directive. It's also recomended
to use a `name` attribute on your form so you can access the
[FormController](https://code.angularjs.org/1.3.0-beta.15/docs/api/ng/type/form.FormController)
and check if the form is valid or not.

You can force a validation by broadcasting the event `schemaFormValidate`, ex
`$scope.$broadcast('schemaFormValidate')`, this will immediately validate the
entire form and show any errors.

Example submit:
```javascript
function FormController($scope) {
  $scope.schema = {
    type: "object",
    properties: {
      name: { type: "string", minLength: 2, title: "Name", description: "Name or alias" },
      title: {
        type: "string",
        enum: ['dr','jr','sir','mrs','mr','NaN','dj']
      }
    }
  };

  $scope.form = [
    "*",
    {
      type: "submit",
      title: "Save"
    }
  ];

  $scope.model = {};

  $scope.onSubmit = function(form) {
    // First we broadcast an event so all fields validate themselves
    $scope.$broadcast('schemaFormValidate');

    // Then we check if the form is valid
    if (form.$valid) {
      // ... do whatever you need to do with your data.
    }
  }
}

```

And the HTML would be something like this:
```html
<div ng-controller="FormController">
    <form name="myForm"
          sf-schema="schema"
          sf-form="form"
          sf-model="model"
          ng-submit="onSubmit(myForm)"></form>
</div>
```


Global Options
--------------
Schema Form also have two options you can set globally via the `sf-options`
attribute which should be placed along side `sf-schema`.

`sf-options` takes an object with the following possible attributes.


| Attribute     |                         |
|:--------------|:------------------------|
| supressPropertyTitles | by default schema form uses the property name in the schema as a title if none is specified, set this to true to disable that behavior |
| formDefaults | an object that will be used as a default for all form definitions |

*formDefaults* is mostly useful for setting global [ngModelOptions](#ngmodeloptions)
i.e. changing the entire form to validate on blur. But can also be used to set
[Validation Messages](#validation-messages) for all fields if you like a bit more
friendlier messages.

Ex.
```html
<div ng-controller="FormController">
    <form sf-schema="schema"
          sf-form="form"
          sf-model="model"
          sf-options="{ formDefaults: { ngModelOptions: { updateOn: 'blur' } }}"></form>
</div>
```



Form types
----------
Schema Form currently supports the following form field types out of the box:

| Form Type     |  Becomes                |
|:--------------|:------------------------|
| fieldset      |  a fieldset with legend |
| section       |  just a div             |
| conditional   |  a section with a ```ng-if``` |
| actions       |  horizontal button list, can only submit and buttons as items |
| text          |  input with type text   |
| textarea      |  a textarea             |
| number        |  input type number      |
| password      |  input type password    |
| checkbox      |  a checkbox             |
| checkboxes    |  list of checkboxes     |
| select        |  a select (single value)|
| submit        |  a submit button        |
| button        |  a button               |
| radios        |  radio buttons          |
| radios-inline |  radio buttons in one line |
| radiobuttons  |  radio buttons with bootstrap buttons |
| help          |  insert arbitrary html |
| tab           |  tabs with content     |
| array         |  a list you can add, remove and reorder |
| tabarray      |  a tabbed version of array |

More field types can be added, for instance a "datepicker" type can be added by
including the [datepicker addon](https://github.com/Textalk/angular-schema-form-datepicker)


Default form types
------------------
Schema Form defaults to certain types of form fields depending on the schema for
a property.


| Schema             |   Form type  |
|:-------------------|:------------:|
| "type": "string"   |   text       |
| "type": "number"   |   number     |
| "type": "integer"  |   number     |
| "type": "boolean"  |   checkbox   |
| "type": "object"   |   fieldset   |
| "type": "string" and a "enum" | select |
| "type": "array" and a "enum" in array type | checkboxes |
| "type": "array" | array |



Form definitions
----------------
If you don't supply a form definition, it will default to rendering the after the defaults taken
from the schema.

A form definition is a list where the items can be
  * A star, ```"*"```
  * A string with the dot notated name/path to a property, ```"name"```
  * An object with that defines the options for a form field., ```{ key: "name" }```

The star, ```"*"``` means "use the default for the entire schema" and is useful when you want the
defaults plus an additional button.

ex.
```javascript
[
  "*",
  { type: 'submit', title: 'Save' }
]
```

The string notation, ```"name"```,  is just a shortcut for the object notation ```{ key: "name" }```
where key denotes what part of the schema we're creating a form field for.


Overriding field types and order
--------------------------------
The order of the fields is technically undefined since the order of attributes on an javascript
object (which the schema ends up being) is undefined. In practice it kind of works though.
If you need to override the order of the forms, or just want to be sure, specify a form definition.

ex.
```javascript
var schema = {
  "type": "object",
  "properties": {
    "surname":     { "type": "string" },
    "firstname":   { "type": "string" },
  }
}

[
  "firstname",
  "surname"
]
```

You can also override fields to force the type and supply other options:
ex.

```javascript
var schema = {
  "type": "object",
  "properties": {
    "surname":     { "type": "string" },
    "firstname":   { "type": "string" },
  }
}

[
  "firstname",
  {
    key: "surname",
    type: "select",
    titleMap: [
      { value: "Andersson", name: "Andersson" },
      { value: "Johansson", name: "Johansson" },
      { value: "other", name: "Something else..."}
    ]
  }
]
```

Standard Options
----------------

General options most field types can handle:
```javascript
{
  key: "address.street",      // The dot notatin to the attribute on the model
  type: "text",               // Type of field
  title: "Street",            // Title of field, taken from schema if available
  notitle: false,             // Set to true to hide title
  description: "Street name", // A description, taken from schema if available, can be HTML
  validationMessage: "Oh noes, please write a proper address",  // A custom validation error message
  onChange: "valueChanged(form.key,modelValue)", // onChange event handler, expression or function
  feedback: false,             // Inline feedback icons
  placeholder: "Input...",     // placeholder on inputs and textarea
  ngModelOptions: { ... },     // Passed along to ng-model-options
  readonly: true               // Same effect as readOnly in schema. Put on a fieldset or array
                               // and their items will inherit it.
}
```

### onChange
The ```onChange``` option can be used with most fields and its value should be
either an angular expression, as a string, or a function. If its an expression
it will be evaluated in the parent scope of the ```sf-schema``` directive with
the special locals ```modelValue``` and ```form```. If its a function that will
be called with  ```modelValue``` and ```form``` as first and second arguments.

ex.
```javascript
$scope.form = [
  {
    key: "name",
    onChange: "updated(modelValue,form)"
  },
  {
    key: "password",
    onChange: function(modelValue,form) {
      console.log("Password is",modelValue);<commit_msg>Docs for htmlClass and fieldHtmlClass<commit_after>Documentation
=============

1. [Basic Usage](#basic-usage)
1. [Handling Submit](#handling-submit)
1. [Global Options](#global-options)
1. [Form types](#form-types)
1. [Default form types](#default-form-types)
1. [Form definitions](#form-definitions)
1. [Overriding field types and order](#overriding-field-types-and-order)
1. [Standard Options](#standard-options)
    1. [onChange](#onchange)
    1. [Validation Messages](#validation-messages)
    1. [Inline feedback icons](#inline-feedback-icons)
    1. [ngModelOptions](#ngmodeloptions)
1. [Specific options and types](#specific-options-and-types)
    1. [fieldset and section](#fieldset-and-section)
    1. [conditional](#conditional)
    1. [select and checkboxes](#select-and-checkboxes)
    1. [actions](#actions)
    1. [button](#button)
    1. [radios and radiobuttons](#radios-and-radiobuttons)
    1. [help](#help)
    1. [tabs](#tabs)
    1. [array](#array)
    1. [tabarray](#tabarray)
1. [Post process function](#post-process-function)
1. [Events](#events)
1. [Manual field insertion](#manual-field-insertion)
1. [Extending Schema Form](extending.md)

Basic Usage
-----------

First, expose your schema, form, and model to the $scope.
Don't forget to load the ``schemaForm` module.

```javascript
angular.module('myModule', ['schemaForm'])
       .controller('FormController', function($scope) {
  $scope.schema = {
    type: "object",
    properties: {
      name: { type: "string", minLength: 2, title: "Name", description: "Name or alias" },
      title: {
        type: "string",
        enum: ['dr','jr','sir','mrs','mr','NaN','dj']
      }
    }
  };

  $scope.form = [
    "*",
    {
      type: "submit",
      title: "Save"
    }
  ];

  $scope.model = {};
}
```

Then load them into Schema Form using the `sfSchema`, `sfForm`, and `sfModel` directives.

```html
<div ng-controller="FormController">
    <form sf-schema="schema" sf-form="form" sf-model="model"></form>
</div>
```

The `sfSchema` directive doesn't need to be on a form tag, in fact it can be quite useful
to set it on a div or some such inside the form instead. Especially if you like to prefix or suffix the
form with buttons or fields that are hard coded.

Example with custom submit buttons:
```html
<div ng-controller="FormController">
  <form>
    <p>bla bla bla</p>
    <div sf-schema="schema" sf-form="form" sf-model="model"></div>
    <input type="submit" value="Submit">
    <button type="button" ng-click="goBack()">Cancel</button>
  </form>
</div>
```

Handling Submit
---------------
Schema Form does not care what you do with your data, to handle form submit
the recomended way is to use the `ng-submit` directive. It's also recomended
to use a `name` attribute on your form so you can access the
[FormController](https://code.angularjs.org/1.3.0-beta.15/docs/api/ng/type/form.FormController)
and check if the form is valid or not.

You can force a validation by broadcasting the event `schemaFormValidate`, ex
`$scope.$broadcast('schemaFormValidate')`, this will immediately validate the
entire form and show any errors.

Example submit:
```javascript
function FormController($scope) {
  $scope.schema = {
    type: "object",
    properties: {
      name: { type: "string", minLength: 2, title: "Name", description: "Name or alias" },
      title: {
        type: "string",
        enum: ['dr','jr','sir','mrs','mr','NaN','dj']
      }
    }
  };

  $scope.form = [
    "*",
    {
      type: "submit",
      title: "Save"
    }
  ];

  $scope.model = {};

  $scope.onSubmit = function(form) {
    // First we broadcast an event so all fields validate themselves
    $scope.$broadcast('schemaFormValidate');

    // Then we check if the form is valid
    if (form.$valid) {
      // ... do whatever you need to do with your data.
    }
  }
}

```

And the HTML would be something like this:
```html
<div ng-controller="FormController">
    <form name="myForm"
          sf-schema="schema"
          sf-form="form"
          sf-model="model"
          ng-submit="onSubmit(myForm)"></form>
</div>
```


Global Options
--------------
Schema Form also have two options you can set globally via the `sf-options`
attribute which should be placed along side `sf-schema`.

`sf-options` takes an object with the following possible attributes.


| Attribute     |                         |
|:--------------|:------------------------|
| supressPropertyTitles | by default schema form uses the property name in the schema as a title if none is specified, set this to true to disable that behavior |
| formDefaults | an object that will be used as a default for all form definitions |

*formDefaults* is mostly useful for setting global [ngModelOptions](#ngmodeloptions)
i.e. changing the entire form to validate on blur. But can also be used to set
[Validation Messages](#validation-messages) for all fields if you like a bit more
friendlier messages.

Ex.
```html
<div ng-controller="FormController">
    <form sf-schema="schema"
          sf-form="form"
          sf-model="model"
          sf-options="{ formDefaults: { ngModelOptions: { updateOn: 'blur' } }}"></form>
</div>
```



Form types
----------
Schema Form currently supports the following form field types out of the box:

| Form Type     |  Becomes                |
|:--------------|:------------------------|
| fieldset      |  a fieldset with legend |
| section       |  just a div             |
| conditional   |  a section with a ```ng-if``` |
| actions       |  horizontal button list, can only submit and buttons as items |
| text          |  input with type text   |
| textarea      |  a textarea             |
| number        |  input type number      |
| password      |  input type password    |
| checkbox      |  a checkbox             |
| checkboxes    |  list of checkboxes     |
| select        |  a select (single value)|
| submit        |  a submit button        |
| button        |  a button               |
| radios        |  radio buttons          |
| radios-inline |  radio buttons in one line |
| radiobuttons  |  radio buttons with bootstrap buttons |
| help          |  insert arbitrary html |
| tab           |  tabs with content     |
| array         |  a list you can add, remove and reorder |
| tabarray      |  a tabbed version of array |

More field types can be added, for instance a "datepicker" type can be added by
including the [datepicker addon](https://github.com/Textalk/angular-schema-form-datepicker)


Default form types
------------------
Schema Form defaults to certain types of form fields depending on the schema for
a property.


| Schema             |   Form type  |
|:-------------------|:------------:|
| "type": "string"   |   text       |
| "type": "number"   |   number     |
| "type": "integer"  |   number     |
| "type": "boolean"  |   checkbox   |
| "type": "object"   |   fieldset   |
| "type": "string" and a "enum" | select |
| "type": "array" and a "enum" in array type | checkboxes |
| "type": "array" | array |



Form definitions
----------------
If you don't supply a form definition, it will default to rendering the after the defaults taken
from the schema.

A form definition is a list where the items can be
  * A star, ```"*"```
  * A string with the dot notated name/path to a property, ```"name"```
  * An object with that defines the options for a form field., ```{ key: "name" }```

The star, ```"*"``` means "use the default for the entire schema" and is useful when you want the
defaults plus an additional button.

ex.
```javascript
[
  "*",
  { type: 'submit', title: 'Save' }
]
```

The string notation, ```"name"```,  is just a shortcut for the object notation ```{ key: "name" }```
where key denotes what part of the schema we're creating a form field for.


Overriding field types and order
--------------------------------
The order of the fields is technically undefined since the order of attributes on an javascript
object (which the schema ends up being) is undefined. In practice it kind of works though.
If you need to override the order of the forms, or just want to be sure, specify a form definition.

ex.
```javascript
var schema = {
  "type": "object",
  "properties": {
    "surname":     { "type": "string" },
    "firstname":   { "type": "string" },
  }
}

[
  "firstname",
  "surname"
]
```

You can also override fields to force the type and supply other options:
ex.

```javascript
var schema = {
  "type": "object",
  "properties": {
    "surname":     { "type": "string" },
    "firstname":   { "type": "string" },
  }
}

[
  "firstname",
  {
    key: "surname",
    type: "select",
    titleMap: [
      { value: "Andersson", name: "Andersson" },
      { value: "Johansson", name: "Johansson" },
      { value: "other", name: "Something else..."}
    ]
  }
]
```

Standard Options
----------------

General options most field types can handle:
```javascript
{
  key: "address.street",      // The dot notatin to the attribute on the model
  type: "text",               // Type of field
  title: "Street",            // Title of field, taken from schema if available
  notitle: false,             // Set to true to hide title
  description: "Street name", // A description, taken from schema if available, can be HTML
  validationMessage: "Oh noes, please write a proper address",  // A custom validation error message
  onChange: "valueChanged(form.key,modelValue)", // onChange event handler, expression or function
  feedback: false,             // Inline feedback icons
  placeholder: "Input...",     // placeholder on inputs and textarea
  ngModelOptions: { ... },     // Passed along to ng-model-options
  readonly: true,              // Same effect as readOnly in schema. Put on a fieldset or array
                               // and their items will inherit it.
  htmlClass: "street foobar",  // CSS Class(es) to be added to the container div
  fieldHtmlClass: "street"     // CSS Class(es) to be added to field input (or similar)
}
```

### onChange
The ```onChange``` option can be used with most fields and its value should be
either an angular expression, as a string, or a function. If its an expression
it will be evaluated in the parent scope of the ```sf-schema``` directive with
the special locals ```modelValue``` and ```form```. If its a function that will
be called with  ```modelValue``` and ```form``` as first and second arguments.

ex.
```javascript
$scope.form = [
  {
    key: "name",
    onChange: "updated(modelValue,form)"
  },
  {
    key: "password",
    onChange: function(modelValue,form) {
      console.log("Password is",modelValue);
{'fraction_non_alphanumeric': 0.15066217306688184, 'fraction_numerical': 0.0032277970285280295, 'mean_word_length': 2.741431362102646, 'pattern_counts': {'":': 40, '<': 49, '<?xml version=': 0, '>': 49, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '291905', 'n_tokens_mistral': 6283, 'n_tokens_neox': 6049, 'n_words': 2281}