Form
The Form is the root element of a ChameleonForms form; you create a Form by either using the <chameleon-form>
tag helper, or instantiating an IForm<TModel>
within a using
block.
The IForm<TModel>
interface looks like this and is in the ChameleonForms
namespace:
/// <summary>
/// Interface for a Chameleon Form.
/// </summary>
/// <typeparam name="TModel">The view model type for the current view</typeparam>
public interface IForm<TModel> : IForm, IDisposable
{
/// <summary>
/// The HTML helper for the current view.
/// </summary>
IHtmlHelper<TModel> HtmlHelper { get; }
/// <summary>
/// The template renderer for the current view.
/// </summary>
IFormTemplate Template { get; }
/// <summary>
/// Writes a HTML String directly to the view's output.
/// </summary>
/// <param name="htmlContent">The HTML to write to the view's output</param>
void Write(IHtmlContent htmlContent);
/// <summary>
/// The field generator for the given field.
/// </summary>
/// <param name="property">The property to return the field generator for</param>
IFieldGenerator GetFieldGenerator<T>(Expression<Func<TModel, T>> property);
/// <summary>
/// Returns a wrapped <see cref="PartialViewForm{TModel}"/> for the given partial view helper.
/// </summary>
/// <param name="partialViewHelper">The HTML Helper from the partial view</param>
/// <returns>The PartialViewForm wrapping the original form</returns>
IForm<TModel> CreatePartialForm(IHtmlHelper<TModel> partialViewHelper);
}
ChameleonForms comes with a standard implementation of the IForm<TModel>
interface that uses the BeginForm
and EndForm
methods in the currently configured form template and returns an instance of the DefaultFieldGenerator
class when asked for a Field Generator.
Default usage
In order to create a self-submitting form using the default form template (see below if you want to adjust it on a per-form basis):
Use the <chameleon-form>
tag helper:
<chameleon-form>
@* Form content goes here *@
</chameleon-form>
By default a self-submitting form, against the page model type, that performs a HTTP post with the browser's default enctype
(usually application/x-www-form-urlencoded
) is outputted, but you can change the submit location, HTTP verb, enctype
, presence of anti forgery token and add any HTML attributes you like using the appropriate parameters, e.g.:
<chameleon-form action="@Url.Action("SomeAction")" method="Post" enctype="Multipart" id="my-form" disabled="false" add-class="a-class" fluent-config='c => c.Attr("data-a", "b")' attr-data-whatever="some value" output-antiforgery-token="false">
@* Form content goes here *@
</chameleon-form>
You can also create a form against a model type different from the page model.
Configuring the form template
As you can see above, when using the BeginChameleonForm
extension method (which is also what the <chameleon-form>
tag helper uses under the hood) it uses helper.GetDefaultFormTemplate()
to determine what form template to use. By default this is set to an instance of the DefaultFormTemplate
class from the ChameleonForms.Templates.Default
namespace.
The way this works is the global configuration will register an implementation of IFormTemplate
with the service collection within your ASP.NET Core web application. The helper.GetDefaultFormTemplate()
extension will then resolve that default template implementation from the request services:
/// <summary>
/// Gets the registered default form template from RequestServices.
/// </summary>
/// <param name="htmlHelper">The HTML Helper</param>
/// <returns>An instance of the default <see cref="IFormTemplate"/></returns>
public static IFormTemplate GetDefaultFormTemplate(this IHtmlHelper htmlHelper)
{
return htmlHelper.ViewContext.HttpContext.RequestServices.GetRequiredService<IFormTemplate>();
}
If you would like to change the form template that is used then simply specify a different type when registering ChameleonForms with the service collection:
services.AddChameleonForms<MyFormTemplate>();
This will new up your form template using a parameterless constructor and then register it as a singleton against IFormTemplate
.
If you want more control on how your template is instantiated and/or registered then you can opt out of ChameleonForms registering your template and instead register it yourself, e.g.:
services.AddChameleonForms(b => b.WithoutTemplateTypeRegistration());
services.AddSingleton<IFormTemplate>(new MyFormTemplate(/* constructor parameters */));
If you want to use multiple Form Templates across your application you can create your own extension methods or create your own tag helper based on the <chameleon-form>
one to allow for different form templates to be specified on a per-form basis.
HTML5 validation
By default, ChameleonForms opts out of HTML5 validation for you via the novalidate="novalidate"
attribute on the <form>
. It does this so that you can retain control of client-side validation (e.g. through unobtrusive validation), which is typically able to yield a better user experience than HTML5 validation.
If you want to override this behaviour you can configure your own form template.
Default HTML
Begin HTML
<form action="%action%" method="%method%" (enctype="%enctype%") (%htmlAttributes%) novalidate="novalidate">
(%antiforgery token%)
End HTML
</form>
Twitter Bootstrap 3 HTML
Same as default.