This post builds on the First Dynamic Form Tag Helper Attempt. This time we are going to introduce small complex typed properties support.
The current version of the dynamic form tag helper is able to iterate over a view model object’s properties and to generate a form group for each simple property. Each form group contains a
input and a validation message
Often times, view model classes contains properties that belongs to user defined types (classes).We refer to this properties as complex properties.
Complex Properties in View Models
Complex types are usually user defined classes that can contain properties belonging to a simple type or to another complex type.
For example, consider the following view model classes:
PersonViewModel class contains the
OwnedDog property which belongs to the
DogViewModel class. Here
OwnedDog is a complex typed property since
DogViewModel is a user defined class.
The dynamic form tag helper needs to take in consideration such properties in order to generate validatable and bindable form controls for the simple properties contained inside complex properties.
Our dynamic tag helper needs to generate the following form, when given an object of the previous
Before we continue, I would like to point out that my current definition of complex types is sloppy, what about generic, iterable, enum and struct types? Are they also consider complex? This is not very clear yet.
In the interest of brevity we are going to stick with this definition. I hope I will refined it as I explore more stuff.
Please take a look at the
IsSimpleType method under the
FormGroupBuilder class for the actual details.
Implementing Complex Property Support
The strategy for generating form groups for complex properties is simple(no pun intended).
We need to iterate over each of the root model properties, if the property is simple, we call the
_getFormGroupForSimpleProperty method and if the property is complex, we call
_getFormGroupForComplexProperty. This is done under the top level and public
_getFormGroupForComplexProperty method iterates over the properties nested inside the complex property and calls the top level
Here we use recursion (
GetFormGroup calls itself through
_getFormGroupForComplexProperty) to attain simple properties buried under arbitrary levels of nesting.
This was sufficient to generate the form groups, the problem is that they are not validatable and bindable yet.
Setting Property Names Properly When Creating ModelExpressions
FormGroupBuilder class instantiates
input and validation
span tag helpers. All of these tag helpers needs a ModelExpression object containing metadata necessary to properly initialize the tag helpers.
Consider the following piece of code:
TagHelper input = new InputTagHelper(generator)
For = new ModelExpression(property.Metadata.PropertyName, property),
Here we pass the property name as available under
Metadata. It turns out that the first argument of the
ModelExpression constructor is used to set the
name html attribute on the generated
input element. Setting the
name html attribute is critical since server side validation and model binding relies on it to properly create the model object from POST request parameters.
This means that we need to make sure that the passed property name is fully qualified with respect to the root model object.
Going back to the Person and Dog example, when building the
ModelExpression when creating an
InputTagHelper for the
Name property under the
DogViewModel class we need to supply the following name:
property.Metadata.PropertyName as in the previous piece of code returns simply
That is why I introduced the following method to handle fully qualified property name building:
In the DynamicFormTagHelper Github repository, you will find the full code that contains an example with 2 levels of complex property nesting that generates the following form:
Try submitting the form with valid and invalid values, you will see that model binding and validation both work.
In an upcoming post we will focus on the case of generic or iterable properties.