<div ng-class="css('rowFluid')">
    <div class="page-header">
        <h1>Schemas</h1>
        Controlling what your inputs look like
    </div>
</div>

<div class="container-fluid schema-page" ng-controller="DemoCtrl">
<div ng-class="css('rowFluid')">
<div class="col-sm-3 span3">
    <affix></affix>
</div>

<div class="affix-section col-sm-9 span9">
<section id="introduction" name="Introduction" affix-scroll>
    <h3>Introduction</h3>

    <p>The most visible part of forms-angular is the <strong>form-input</strong> directive which
        takes a <em>schema</em> in the scope and creates inputs. These schemas can be very simple as in the
        example below:</p>
    <pre>&lt;div ng-init="name=[{name:'surname'},{name:'forename']"&gt;
    &lt;form-input schema="name" /&gt;
&lt;div&gt;</pre>
    <p>This simple bit of markup creates a small schema and stores it in the scope as <em>name</em> (you
        wouldn't normally it like this, but it illustrates things well) then invokes the form-input directive,
        telling it to use the schema just created to create a form with the appropriate input fields.</p>

    <div class="well well-sm well-small" ng-init="name=[{name:'surname'},{name:'forename'}]">
        <form-input schema="name" noautofocus="true" /> <!--Add a noautofocus here otherwise the resulting form stops the page scrolling to the internal links-->
    </div>
    <pre ng-show="record">Record content: {{record}}</pre>

    <p>There is more information about the forms-input directive on the <a href="/#!/forms">forms page</a>.</p>
</section>
<section id="formschema" name="Form Schemas" affix-scroll>
    <h3>Form Schemas</h3>

    <p>The form-input directive can get a good deal richer than the simple example above.  The following
        options are available in a form schema element:</p>
    <ul>
        <li><strong>type</strong> sets the type of input control generated.  In addition to the
            <a href="http://www.html5rocks.com/en/tutorials/forms/html5forms/">standard
                HTML5 types</a> there are some 'special' types:<ul>
                <li><strong>textarea</strong> a textarea control</li>
                <li><strong>radio</strong> a radio button control</li>
                <li><strong>select</strong> a select control</li>
            </ul></li>
        <li><strong>id</strong> specifies the id of the input field (which defaults to f_<em>name</em>)</li>
        <li><strong>label</strong> specifies the label of the input field (which defaults to <em>name</em> converted to title case)</li>
        <li><strong>required</strong> validates the field</li>
        <li><strong>placeHolder</strong> allows placeholder text to be specified</li>
        <li><strong>showWhen</strong> either:<ol><li>an object of the form {lhs:variable, comp:comparison, rhs:variable} where:<ul>
            <li><strong>variable</strong> can be a string, number or field in the model preceded by <strong>$</strong></li>
            <li><strong>comparison</strong> is one of 'eq', 'ne', 'gt', 'gte', 'lt', 'lte'</li></ul><p>or</p>
        </li><li>an angular expression</li></ol>
        </li>
    <li><strong>help</strong> is for specifying help text</li>
    <li><strong>helpInline</strong> is for specifying help text which is displayed inline</li>
    <li><strong>add</strong> allows anything else to be added to the input html.  For example
        <code>"add": "ui-date ui-date-format "</code> (note the space at the end - add always needs this)
        brings up the angular-ui date picker.
    </li>
    <li><strong>rows</strong> (in conjunction with a textarea type) allows the depth of the control to be
        specified.  The <strong>auto</strong> option creates a textarea that automatically expands</li>
    <li><strong>options</strong> (in conjunction with a select or radio type) allows the options for the select / radio button group to
        be specified.  You can either do this by passing the option values in an array and passing it directly,
        or by putting them in an array on the scope and passing the name of the array (which allows run-time
        modification</li>
</ul>

    <h5>Example</h5>
    <pre>&lt;div ng-init="example2=[
        {name:'surname',label:'Family Name',required:true},
        {name:'forename',id:'fnameinput'},
        {name:'dateOfBirth',type:'date'},
        {name:'sex',type:'radio',options:['male','female']},
        {name:'hairColour',type:'select',options:['brown','black','blonde','grey']}]"&gt;
    &lt;form-input schema="example2" /&gt;
&lt;div&gt;</pre>
    <p>which looks like:</p>
    <div ng-init="colours=['brown','black','blonde','grey']"></div>
    <div class="well well-sm well-small" ng-init="example2=[
        {name:'surname',label:'Family Name',required:true},
        {name:'forename',id:'fnameinput'},
        {name:'dateOfBirth',type:'date'},
        {name:'sex',type:'radio',options:['male','female']},
        {name:'hairColour',type:'select',options:['brown','black','blonde','grey']}]">
        <!--Add a noautofocus & forceform here and modify the model-->
        <form>
            <form-input schema="example2" model="exampledata" forceForm="true" noautofocus="true" />
        </form>
    </div>
    <pre ng-show="exampledata">Record content: {{exampledata}}</pre>

</section>

<section id="mongoose" name="Mongoose Schemas" affix-scroll>
    <h3>Mongoose Schemas</h3>

    <p>Mongoose is a popular package that simplifies using MongoDB with Node JS. Mongoose requires that
        a schema is created for each 'model'. As you will have seen in the <a href="/#!/get-started">Get
            Started</a> section, <strong>forms-angular</strong> (specifically the BaseCtrl controller)
        can convert Mongoose schemas into the schemas that
        the form-input directive uses, which saves a lot of coding by hand and makes it very easy to
        keep your front and back ends in sync.  If you use BaseCtrl, then you should set the <strong>schema</strong>
        attribute of the form-input tag to "baseSchema()".</p>

    <p>As many models as you want can be registered with forms-angular by calling the <code>addResource</code>
        method of the forms-angular object as <a href="/#!/get-started#server-code">shown</a> in the
        Get Started section. If you have more than a few models it is a good idea to put them in their own
        directory and loop through it.</p>

    <p>A trivially simple schema looks like this:</p>
            <pre>var ApplicantSchema = new Schema({
    surname: {type:String, required:true, index:true},
    forename: {type:String, index:true},
});</pre>
    <p>Each schema element (or field) has a type and optionally a number of other properties. Many of these properties
        are used by forms-angular to generate appropriate behaviour on the front end. The appropriate input types are
        used (for instance an <strong>enum</strong>string) attribute will generate a select control (you can specify radio button - see below)
        and client side validation keeps round trips down (we cannot say "to a minimum" as work remains to
        be done in this area).</p>

    <p>You can get an idea of what forms-angular does with a vanilla Mongoose JS schema by looking at <a href="/code/a_unadorned_mongoose.js">this schema</a> and <a href="/#!/a_unadorned_mongoose/new">the
        form generated from it</a>.</p>

    <p>For comprehensive information about Mongoose schemas visit the <a href="http://mongoosejs.com/docs/guide.html">Mongoose JS website</a>.</p>
</section>
<section id="list-fields" name="List Fields" affix-scroll>
    <h3>List Fields</h3>

    <p>In a couple of places forms-angular uses the concept of 'list fields' - fields that generally allow
        the user to quickly see
        what they are dealing with - for example in the case of a person the forename and surname would be
        list fields. They don't
        have to be unique, they just have to be useful. List fields are used:</p>
    <ul>
        <li>When populating select options when a model is referenced by another model</li>
        <li>In list forms - where the contents of a collection are displayed</li>
        <li>In search results (though this can be overridden)</li>
        <li>In reports when a model is referenced by another model and a columnTranslation is used</li>
    </ul>

    <p>A field may be specified to be a list field by adding a truthy value for a <strong>list</strong> key
        in the schema element: <code>forename: {type:String, list:true}</code></p>

    <p>List fields can be generated on both the front and back end, and it is done as follows:</p>
    <ol>
        <li>If there is at least one schema element with a truthy value for <strong>list</strong> then all
            such fields are list fields
        </li>
        <li>If no field is specified as a list field then:</li>
        <ul>
            <li>On the client the first non hidden string field is used or failing that the first field</li>
            <li>On the server the first two fields are used (one day there will hopefully be some
                consistency here!)
            </li>
        </ul>
    </ol>
</section>

<section id="form-object" name="The form Object" affix-scroll>
    <h3>The <em>form</em> Object</h3>

    <p>The mark-up of generated forms can be influenced by use of the <strong>form</strong> object in the
        schema type: <code>surname: {type:String, form:{label:'Family Name', size:'large'}}</code></p>

    <p>The form object can have the following optional keys:</p>
    <ul>
        <li><strong>type</strong> the input type to be generated - which must be compatible with the Mongoose type.
            Common examples are <em>email</em>, <em>url</em>.  Note that if the field type is String and the name (or label) contains the string 'password'
            then type="password" will be used <em>unless</em> type="text".  If the Mongoose schema has an <em>enum</em>
            array you can specify a radio button group (instead of a select) by using a type of <em>radio</em></li>.
        <li><strong>hidden</strong> inhibits this schema key from appearing on the generated form.</li>
        <li><strong>label</strong> overrides the default input label. label:null suppresses the label
            altogether.
        </li>
        <li><strong>placeHolder</strong> adds placeholder text to the input (depending on data type).</li>
        <li><strong>help</strong> adds help text under the input.</li>
        <li><strong>helpInline</strong> adds help to the right of the input.</li>
        <li><strong>popup</strong> adds popup help as specified.</li>
        <li><strong>order</strong> allows user to specify the order / tab order of this field in the form.  This
            overrides the position in the Mongoose schema.</li>
        <li><strong>size</strong> sets <a href="http://twitter.github.io/bootstrap/base-css.html#forms">control
            width</a>.
            Options are: mini, small, medium (default), large, xlarge, xxlarge and block-level.
        </li>
        <li><strong>readonly</strong> adds the readonly attribute to the generated input (doesn't work with
            date - and perhaps other types). </li>
        <li><strong>select2</strong> in an enum field or a reference field tells the system to use the
            <a href="http://ivaynberg.github.io/select2/"><em>select2</em></a> control rather than a
            <em>select</em>. If the number of options is large in a reference field then
            <strong>select2:{fngAjax:true}</strong> instructs the program to use ajax calls to query
            the server rather than downloading the table. The values in the select2 control come
            from the <a href="#listing">listing fields</a>.
        </li>
        <li><strong>rows</strong> sets the number of rows in inputs (such as textarea) that support this.
            Setting rows to <strong>"auto"</strong> makes the textarea expand to fit the content, rather than create a
            scrollbar.</li>
        <li><strong>tab</strong> used to divide a large form up into a tabset with multiple tabs
        (see <a href="/#!/i_tabbed_forms/new">example</a>).
        </li>
        <li><strong>showWhen</strong> allows conditional display of fields based on values elsewhere.  For example having
            prompted whether someone is a smoker you may want a field asking how many they smoke a day:
<pre><code>smoker: {type: Boolean},
howManyPerDay: {type: Number, form:{showWhen:{lhs:"$smoker", comp:"eq", rhs:true}}}</code></pre>
            <p>As you can see from the example there are three parts to the showIf object:</p>
            <ul>
                <li><strong>lhs</strong> (left hand side) a value to be compared.  To use the current value of another
                    field in the document preceed it with $.</li>
                <li><strong>comp</strong> supported comparators are 'eq' for equality, 'ne' for not equals,
                    'gt' (greater than), 'gte' (greater than or equal to), 'lt' (less than) and 'lte' (less than or equal to)</li>
                <li><strong>rhs</strong> (right hand side) the other value to be compared.  Details as for lhs.</li>
            </ul>
        </li>
        <li><strong>noAdd</strong> inhibits an Add button being generated for arrays.</li>
        <li><strong>noRemove</strong> inhibits a Remove button being generated for array elements.</li>
        <li><strong>add</strong> allows arbitrary attributes to be added to the input tag. Useful for adding
            classes.</li>
        <li><strong>inlineRadio</strong> (only valid when type is radio) should be set to true to present all radio button options in a single line</li>
        <li><strong>editor</strong> (only valid when type is textarea) should be set to <em>ckEditor</em> to use <a href="http://ckeditor.com">CKEditor</a></li>
        <li><strong>directive</strong> allows you to specify custom behaviour.  Gets passed attributes from form-input (with
            <em>schema</em> replaced with the current element - so <em>add</em> can be used to pass data into directives).</li>
        <li><strong>customSubDoc</strong> (only valid on a sub document) allows you to specify custom HTML (which may include directives) for the sub doc</li>
        <li><strong>customFooter</strong> (only valid on a sub document) allows you to specify custom HTML (which may include directives) for the footer of a group of sub docs</li>
        <li><strong>formstyle</strong> (only valid on a sub schema) sets style of sub form. See <a href="/#!/forms#form-styles">form style section</a> for options.
        </li>
        <li><strong>link</strong> sets up hyperlinks for reference fields as follows:
            <ul>
                <li><em>linkOnly</em> if true (which at the time of writing is the only option supported)
                    then the input
                    element is not generated.
                </li>
                <li><em>text</em> the text used for the link.</li>
            </ul>
        </li>
    </ul>

    <p><a href="/code/b_using_options.js">This example schema</a> and <a href="/#!/b_using_options/new">this
        form</a> shows many of these options in use.</p>

</section>

<section id="containers" name="Containers" affix-scroll>
    <h3>Containers</h3>

    <p>Sometimes it is hard within a Mongoose schema to detail exactly how you want the associated form
        or forms to be laid out. One particular class of layout features that currently cannot be
        requested within a Mongoose schema are containers. Hopefully this will be addressed in a forthcoming
        release
        but if you need them now then you need to create a schema by hand (or dynamically in code).</p>

    <p>An example of a use of containers would be:</p>
    <pre>&lt;form-input ng-init="names=[
  {containerType:'fieldset',title:'Name',content:
    [
      {id:'f_surname',label:'Surname',name:'surname',type:'text'},
      {id:'f_forename',label:'forename',name:'forename',type:'text'}
    ]
  }
]" schema="names"&gt;&lt;/form-input&gt;</pre>
    <p>Other containers are <strong>tab</strong>,
        <strong>well</strong>, <strong>well-large</strong> and <strong>well-small</strong>.</p>

    <p>If you want to "roll your own" you can do something like:</p>
    <pre>&lt;style&gt;
  .redBorder {border:solid 2px red;}
  p.bigRed {color: red; font-size: large}
&lt;/style&gt;
&lt;form-input ng-init="names=[
  {containerType:'redBorder',title:'Name',titleTagOrClass:'bigRed',content:
    [
      {id:'f_surname',label:'Surname',name:'surname',type:'text'},
      {id:'f_forename',label:'forename',name:'forename',type:'text'}
    ]
  }
]" schema="names"&gt;&lt;/form-input&gt;
</pre>
    <p>Where container type is seen as a class for a div and a titleTagOrClass of h1..h6 is interpreted as a
        heading tag and anything else as a class to be applied to a paragraph (as in the example).  If a title is
        specified without a corresponding titleTagOrClass then &lt;h4&gt; is used as a default.</p>

    <p>If you need even more flexibility then you can create a function that returns an object of the form
        {before: <em>markup before container contents</em>, after:<em>markup after container contents</em>}.</p>
</section>

<section id="custom" name="Custom Schemas" affix-scroll>
    <h3>Custom Schemas</h3>

    <p>It is easy to create custom form schemas which are a subset of the whole schema by specifying the
        fields to include and any options. See the static in <a href="/code/b_using_options.js">this example</a>.
        The custom form schemas are invoked as follows:
    </p>
    <ul>
        <li><strong>/#/:model/:formschema</strong> (<a href="/#!/b_using_options/justnameandpostcode/">example
            here</a>)
        </li>
        <li><strong>/#/:model/:formschema/new</strong> (<a href="/#!/b_using_options/justnameandpostcode/new">example
            here</a>)
        </li>
        <li><strong>/#/:model/:formschema/:id/edit</strong></li>
    </ul>

    <h4>Subkeys</h4>
    <p>Custom schemas are a good way to allow access to only part of a document, for instance if a customer record contained operational
        and accounts information an accounts user would require a different view of the data (that would include account balance)
        than a user from operations (who would not have access to the account balance).  Consider the following:</p>
    <pre><code>var AddressSchema = new Schema({
        type: { type: String, default: 'Home', enum: ['Delivery', 'Invoice', 'Historic'] },
        street: String,
        town: String,
        postalCode: String
        }, {_id: false});</code></pre>
    <p>and in the customer model</p>
    <pre><code>addressList: {type: [AddressSchema], mergeKey: 'type', form: {pane: 'Address', labels: 'Addresses'}}</code></pre>
    <p>We need a way of having the delivery address appear on one form (for the operation user) and the invoice address on the
        finance form, even though they are in the same field.</p>
    <p>forms-angular has the concept of a <strong>subkey</strong> for this scenario.  The custom schema for the operations user would contain:</p>
    <pre><code>addressList: {subkey:
  {keyList: {type: 'Delivery'}, containerType: 'well-small', title: 'Address', titleTagOrClass: 'h5'}
}</code></pre>
    <p>while that for finance might include</p>
    <pre><code>addressList: {subkey:
  [
    {keyList: {type: 'Invoice'}, containerType: 'well-small', title: 'Invoice To:'},
    {keyList: {type: 'Delivery'}, containerType: 'well-small', title: 'Deliver To:'}
  ]
}</code></pre>
    <p>Note that subkey can be an object or an array of objects.  Where there are multiple sub docs that match the subkey the first will be used.</p>
</section>
</div>
</div>
</div>