Since the last post, the dynamic form tag helper supports generating form groups for complex properties.
Now the html generated by the dynamic form tag helper is not customizable and it would be nice if it was.
There might be numerous reasons for customizing the default behavior, but we are going to focus on the following: styling and using custom html form controls.
In this post we are going to introduce capabilities for tweaking some default behavior and adding custom css classes by using a nested tag helper.
The full code is in the usual Github repository.
We are going to add capability for tweaking the following form elements:
- The text content of the submit button
- The css classes of the submit button
- For a specific property(form group):
- Choosing a custom
inputelement razor template
- Adding css classes to the generated
<input>or validation message
- Choosing a custom
Consider the following form:
Arbitrary css classes have been applied to the BirthDate
label as well as to the “Person’s full name”
input element. This is what makes the BirthDate
label purple and the “Person’s full name”’s text yellowish green(not the real color’s name ;-)).
In addition, a custom date time picker widget has been used for the BirthDay field. Here I used the bootstrap datetimepicker which allows to select dates more conveniently.
Let’s now take a look on how to achieve this.
Customizing behavior with the TweakTagHelper
Let’s consider the usage of the dynamic tag helper in the following
Here you will notice the usage of the new
tweak nested tag helper.
TweakTagHelper is intended to be used inside the
DynamicFormTagHelper in order to modify the generation behavior of a form group related to a specific property.
In this regard, it can accepts one of the view model’s properties as an argument along with the aspects to customize, which can be one of the following:
asp-input-paththe path to a custom html form control
asp-validation-classesthe additional css classes that are going to be added to the relevant form group element(
It is possible to target properties nested under complex types as we can see in the last used
DynamicFormTagHelper has been modified to read customization configuration and to take it in account. We are going to see later how this capability is implemented.
Customizing the Submit Button
Two attributes have been added to the
asp-submit-button-textfor specifying the text content
asp-submit-button-classesfor specifying additional css classes for the submit button
Here is an example usage:
This sets the submit button text to “Create Person!” and adds the
btn-success class to it.
Reading Tweaking Configuration in the DynamicFormTagHelper
Consider the following snippet from the
DynamicFormTagHelper.ProcessAsync method we create an object belonging to the
TweakingConfiguration class, we pass this object to the
context object and we launch the execution of the children tag helpers content.
TweakingConfiguration object acts as a data transfer object that is going to be populated by the children
As we can see in the following example the
TweakingConfiguration object named
tweakConfig is subsequently passed to the
FormGroupBuilder.GetFormGroup method and is also used directly to properly generate the submit button:
Transferring Data from the TweakingTagHelper to the DynamicFormTagHelper
As we saw in The Very Basics of Nesting for Tag Helpers, child to parent communication is performed via the
TagHelperContext object that is passed to each of the parent and children
Let’s consider the following code it’s the actual
TweakingTagHelper class implementation:
HtmlTargetElement attribute is slapped on the tag helper class to allow its usage only under the
dynamic-form tag helper.
Then, you can see that
TweakTagHelper defines the properties mapped to the relevant html attributes.
TweakTagHelper.ProcessAsync creates a
PropertyTweakingConfiguration object that represents the customization of a specific property. The created instance is then added to the
TweakingConfiguration object fetched from the
TagHelperContext. Keep in mind here that the fetched
TweakingConfiguration instance is the same one referenced by the
dynamic-form tag helper.
Here we can see that the
TweakTagHelper fulfills a very simple responsibility: reading data from the cshtml view and passing its parent tag helper (
dynamic-form) in a convenient format.
Now let’s get to the
Using the Tweaking Configuration inside the FormGroupBuilder
First off, the
FormGroupBuilder has been modified and became a regular class (as opposed to a static class).
As you might know the form generation process depends on the following services:
IHtmlGenerator and recently
Passing the instances of these services to each method involved in the form group rendering process became painful so I refactored it to a regular class with the previous dependencies defined as private fields.
Then, a new argument
tweakingConfig argument as been added to the
FormGroupBuilder.GetFormGroup method. This argument is expected to contain the
TweakingConfiguration object built by the various
tweak tag helpers used.
tweakingConfig object is then passed to the private methods responsible for rendering the elements of the form group in order to allow them to take the tweaking configuration into account.
Custom Template Rendering
Let’s take a look at the private
When a tweaking configuration is available for the currently processed
property and the configuration defines a form control template via the
InputTemplatePath property, the specified template is rendered instead of the default
renderInputTemplate method uses the
IHtmlHelper.Editor method to render the form control:
The previous method uses a classic
IHtmlHelper take a look at Using the old HtmlHelper inside tag helpers for more details.
Adding Custom CSS Classes
Adding custom css classes is straightforward, we just pass a
TagHelperAttributeList populated with the developer defined classes to the existing
GetGeneratedContentFromTagHelper method as in the following
Notice here the usage of the C# 6 null conditional operator when passing the eventually configured classes.
In this attempt, we showed that it was possible to introduce configurability via nested tag helpers to the
dynamic-form tag helper.
Usually developers would want to influence the form rendering via the model class and the attributes slapped on it and its properties. But it could be cleaner to specify some stuff in the cshtml view such as css classes.
A lot of work still needs to be done to make the
dynamic-form tag helper more reliable and usable, at this point it is just a prototype.
Finally, using the
HtmlHelper.Editor reminded me of the old
DisplayTemplates facility which allowed to place display and editor templates named after a specific type in a specific location for later use via the
EditorFor is able to generate a form control for a specific property and is able fetch a custom editor templates by type name automatically if it is placed under
That allowed the developer to specify a default editing widget for a specific type.
I wonder if we could bring this capability to tag helpers…