Field
The Field is a single data collection unit; you create a Field by using the <field>
tag helper, calling the Field
method on a Section or otherwise instantiating and outputting to the page a Field<TModel>
.
You can also create a parent field that can have child fields nested within it by instantiating nesting things within a non-self-closing <field>
tag helper or creating a Field<TModel>
within a using
block (the start and end of the using
block will output the start and end HTML for the Field and the contents of the using
block will output the child Fields).
The Field<TModel>
class is defined as follows in the ChameleonForms.Component
namespace:
/// <summary>
/// Wraps the output of a single form field.
/// </summary>
/// <typeparam name="TModel">The view model type for the current view</typeparam>
public class Field<TModel> : FormComponent<TModel>
{
/// <summary>
/// Creates a form field.
/// </summary>
/// <param name="form">The form the field is being created in</param>
/// <param name="isParent">Whether or not the field has other fields nested within it</param>
/// <param name="fieldGenerator">A field HTML generator class</param>
/// <param name="config">The configuration values for the field</param>
public Field(IForm<TModel> form, bool isParent, IFieldGenerator fieldGenerator, IFieldConfiguration config)
: base(form, !isParent) {...}
...
}
The HTML for a Field is generated via the Field
method in the form template (or BeginField
and EndField
for the start and end HTML for a parent field).
A Field consists of 8 sub-components:
- Field Element - The HTML that makes up the control(s) to accept data from the user
- Field Label - Text that describes a Field Element to a user (and is linked to that Field Element)
- Field Validation HTML - Markup that acts as a placeholder to display any validation messages for a particular Field Element
- Field Configuration - The configuration for a particular Field, Field Element and/or Field Label
- Hint - Any hint text that is specified against the field
- Required designator - A visual designator to indicate that the field is required
- Prepended and appended HTML - Any prepended or appended HTML specified against the field to be added before / after the Field Element
- Field container - The containing element surrounding the Field Element and other relevant parts of the field
The form template determines how to lay out these sub-components.
Default usage
Manually specify HTML
If you want to define your own HTML for the Field Element, Field Label and Field Validation HTML then you can do so by using the manual
attribute on the <field>
tag helper and nest <manual-element>
, <manual-label>
and <manual-validation>
elements to specify the Field Element, Field Label and Field Validation HTML, e.g.:
<form-section heading="Title">
<field manual>
<manual-element><strong>Element</strong></manual-element>
<manual-label><strong>Label</strong></manual-label>
<manual-validation><strong>validation</strong></manual-validation>
</field>
Or, if you want to specify the optional model metadata, valid state and field configuration:
@inject ICompositeMetadataDetailsProvider MetadataDetailsProvider
...
<form-section heading="Title">
<field manual model-metadata="new DefaultModelMetadataProvider(MetadataDetailsProvider).GetMetadataForType(typeof(int))" is-valid="true" append="After Element" prepend="Before Element">
<manual-element><strong>Element</strong></manual-element>
<manual-label><strong>Label</strong></manual-label>
<manual-validation><strong>validation</strong></manual-validation>
</field>
</form-section>
Note: the way that the manual field is implemented allows for quite a bit of extensibility by defining custom tag helpers that define the various parts of your field. See the implementations for <manual-element>
etc. for an idea of how to do that.
Use a Field Generator to output a single field in a Section
If you would like ChameleonForms to use a Field Generator to generate the HTML for the Field Element, Field Label and Field Validation HTML from a field on the model then you can use the <field>
tag helper, e.g.:
<form-section heading="Title">
<field for="FieldOnTheModel" />
@* and you can add field configuration: *@
<field for="FieldOnTheModel" placeholder="Placeholder text" ... />
<field for="FieldOnTheModel" fluent-config='c => c.ChainFieldConfigurationMethodsHere()' />
</form-section>
Use a Field Generator to output a parent field in a Section
If you want to use a Field Generator and want to nest child Fields under a Field then you can use a non self-closing <field>
tag helper, e.g.:
<form-section heading="Title">
<field for="FieldOnTheModel">
@* Child Fields *@
</field>
</form-section>
Use a Field Generator to output a single field in a parent Field
If you want to use a Field Generator to create nested Fields under a parent Field then you can nest <field>
tag helpers within the parent <field>
, e.g.:
<field for="FieldOnTheModel">
<field for="ChildField" />
</field>
Default HTML
Field
<dt>%labelHtml% %requiredDesignator%</dt>
<dd class="%fieldContainerClasses%">
%prependedHtml% %fieldElement% %appendedHtml% %hint% %validationHtml%
</dd>
Required designator
The %requiredDesignator%
is shown if the field is required:
<em class="required">*</em>
If you want to override the required designator look at Creating custom form templates > Field.
Hint
The %hint%
is shown if a hint is specified in the Field Configuration:
<div class="hint" id="%fieldId%--Hint">%hint%</div>
If a hint is added then an aria-describedby="%fieldId%--Hint"
attribute value will automatically be added to the field element to improve accessibility.
Begin HTML (parent)
<dt>%labelHtml% %requiredDesignator%</dt>
<dd class="%fieldContainerClasses%">
%prependedHtml% %fieldElement% %appendedHtml% %hint% %validationHtml%
<dl>
End HTML (parent)
</dl>
</dd>
Twitter Bootstrap 3 HTML
Field: Input (except checkbox and file upload), textarea or select control
<div class="form-group%if !isValid% has-error%endif%%fieldContainerClasses%">
%if withoutLabel%<span class="control-label">%endif%
%labelHtml class="control-label"%
%if withoutLabel%</span>%endif%
%if isInputGroup or isRequired%
<div class="input-group">
%endif%
%prependedHtml%
%fieldElement class="form-control"%
%appendedHtml%
%if isRequired%
<div class="input-group-addon required">%requiredDesignator%</div>
%endif%
%if isInputGroup or isRequired%
</div>
%endif%
%hint%
%validationHtml class="help-block"%
</div>
Field: Single checkbox
<div class="checkbox%if !isValid% has-error%endif%%fieldContainerClasses%">
%prependedHtml%
%fieldElement%
%requiredDesignator%
%appendedHtml%
%hint%
%validationHtml class="help-block"%
</div>
Field: Radio/Checkbox list
<div class="form-group%if !isValid% has-error%endif%%fieldContainerClasses%">
<span class="control-label">
%labelHtml% %requiredDesignator%
</span>
%prependedHtml%
%fieldElement%
%appendedHtml%
%hint%
%validationHtml class="help-block"%
</div>
Field: Other (e.g. file upload)
<div class="form-group%if !isValid% has-error%endif%%fieldContainerClasses%">
%if withoutLabel%<span class="control-label">%endif%
%labelHtml% %requiredDesignator%
%if withoutLabel%</span>%endif%
%prependedHtml%
%fieldElement%
%appendedHtml%
%hint%
%validationHtml class="help-block"%
</div>
Common elements
The %requiredDesignator%
is shown if the field is required:
<em class="required" title="Required">∗</em>
The %hint%
is shown if a hint is specified in the Field Configuration:
<div class="help-block form-hint" id="%fieldId%--Hint">%hint</div>
Input Groups
If the Field Element is within an input group then the prepended and appended HTML will be wrapped in the following:
<div class="input-group-addon">%html%</div>
A field is in an input group if:
- The field is an input (except checkbox and file upload), textarea or select control and:
- The field is required (since the Form Template appends the required designator as an input group add-on); or
- You use the
AsInputGroup
extension method from theChameleonForms.Templates.TwitterBootstrap3
namespace on theIFieldConfiguration
In all other situations you will manually need to add wrapping HTML with the relevant classes (e.g. using Append
and Prepend
on the Field Configuration).
As an example of what you can do with the input group consider the following:
<field for="Dollars" fluent-config='c => c.AsInputGroup()' prepend="$" append=".00" />
This will render like this:
In order to be able to swap out the extension method usage across your application easily if you change your form template we recommend that rather than adding a using statement to ChameleonForms.Templates.TwitterBootstrap3
for each view that has a form using the extension method you instead add the namespace to your _ViewImports.cshtml
file.
Parent field
Begin HTML
The HTML is the same as the Field HTML specified above, but the last </div>
is replaced with:
<div class="row nested-fields">
<div class="col-xs-1"></div>
<div class="col-xs-11">
End HTML
</div>
</div>
</div>