Angular 4+, Empower Dynamic Form, Part 2: Make It Better

We had a simple yet good start on dynamic form in the part one of Empower Dynamic Form. We made it work. Now, we need to make it better (much better). I reckon CSS is either too simple or too boring for us. Imagine that you spend hours playing on CSS, and when the others looking at the page with your favorite design, they might say it is pretty beautiful or ugly depending on their mood. Believe me, it is fun to have a GUI review meeting…

So, I decided not to add the CSS to give you the chance to comment on it. The agenda for us is to make the form structurally enriched. In another word, make the form more powerful to handle more complicated GUI models.

Quite often, we have a group of HTML elements that we want to demarcate. We want to display/handle them in a way that it looks like the elements are from the same clan.

Let’s re-organize the model to include two groups:

  • Previous, we have Type “My Lady” and “My Man”. Now, let’s add a group Sex to indicate how attractive the residents are. Group Sex has two DropDown elements: Type “My Lady” and “My Man”, and Sexy “Yes!” and “Oh, Yeah!”
  • A new group Address is added to record where the residents live. The group has one TextField element Street and one DropDown element Location.

To tailer our model to include the new groups, we add two new classes under src/app/model.

address.ts to represent the Address group:

sex.ts to represent the Sex group:

Modify myModelParam.ts to include the new parameters sexy, street, and location for new groups (The bold sections are the parts changed from part 1 codes):

Modify myModel.ts to include the new groups, Sex and Address:

As you might already know, in Angular, we use FormGroup to group the set of elements as the GUI control. In this section, we are going to look at how to configure the group elements, and how to convert our group element configuration to the FormGroup.

In part one, we used the FormElement to represent/configure the elements on the HTML page. For example, a TextField represents a input field, DropDown represents a select field. Similarly, to configure a group of elements, we introduce a new sub-class of FormElement: Group, which will reside under src/app/group-element/. Wait a minute, why/how do we get the src/app/group-element/ directory?

In order to organize/display the group elements gracefully, we will need a new component, group-element, so that the group-element can reuse the previous form-element component and group-element component itself in a recursive manner.

To generate group-element:

This will generate the group-element component under src/app/group-element/.

Here we are. That is why/how we get the src/app/group-element/ directory. Our group.ts lives happily inside src/app/group-element/:

If you are familiar with design patterns, here is an example of Composite Pattern, where Group serves as the composite of its leaves and itself. If there are nested groups in elements, toFormGroup method recursively converts the group configuration to a map of FormGroup, and then toFormControl method converts everything in the group to the final FormGroup.

Note that we also added the elements field to ElementParam class to allow elements being configured:

Now, with the Group class as a new form element for configuration, we can easily convert a form configuration with group elements to FormGroup. There is no change on toFormGroup method of FormFactory class (how nice it is!). We simply add the groups/elements configuration to elements of FormFactory as we desire. Here is a the FormFactory class with a new form configuration:

As you see, the only part that is changed in FormFactory class is how the elements is constructed. We added two groups in it. You could play with the elements configuration, and the output form will be changed magically.

Here is how the page looks like:

When the form is submitted, it generates the model as:

Let’s say Adam like apples, and he plants apple trees (That is right. Adam’s apple…). He lives under the tree. When registering Adam, we have:

When the form is submitted, it generates the model as:

Amazing, right? Hold on, it is not over yet. If we change the elements configuration in FormFactory class, for Group sex and address, we change layout from fx: 'column' to fx: 'row'. We have:

Fantastic, right? Hold on, it is not done yet. We just have the model and configuration covered so far. How about the group-element component? How about the form component? That is right, we are totally not done yet… Following section will bring you the magics.

The group-element component is used to render the groups, which in turn renders the elements inside the group.

group-element component’s magics comes from two files:

  • group-element.component.html the HTML template for group elements
  • group-element.component.ts the class that supports the template

In group-element.component.html, we have:

  • *ngFor iterates the elements in the group element element.
  • app-form-element renders the elements inside the group.
  • app-group-element renders the nested groups if there is any.
  • Note [formGroup]="group" , wheregroup represents the FormGroup of the group element being rendered.
  • Similarly, note [group]="group.get(elemt.name)", where [group] is the input of nested app-group-element for FormGroup. The group.get(elemt.name) retrieves the nested FormGroup for the nested group. (Remember in Group class, when we converted the configuration to FormGroup, we used the element name of Group as the nested group name.)

In group-element.component.ts, we have:

We also need a little bit change in the template page that assembles the elements for the form, which is in form.component.html:

  • The bold section is the part changed from part 1 code. According to the element type elemt.elementType, this template renders the app-form-element or app-group-element accordingly.
  • The [group] input of app-group-element is used to denote the FormGroup that is associated with the Group element. The FormGroup for this app-group-element is retrieved by form.get(elemt.name).

I think that is all for the magics of the group elements. I hope you enjoy it.

Hold on, we are not done yet. Of course, we have Part 3 coming, stay tuned!

Life is beautiful…