Suite Forms¶
When developing Suite Applications, we need to make sure that the UI is standard across them all.
In order to make sure all forms look the same, the Suite provides a set of
Standard Form Controls for the most common scenarios, like text, password, date,
multi-selection, etc. Basically, instead of using plain input
s, you must use
the Suite's Form Controls.
When the Suite's Standard Controls are not enough, you can quickly create your own Custom Form Control.
In addition, in order to build complex forms quickly, the Suite provides helpers for building FormGroups and FormArrays.
Concepts¶
Before we dive in, let's define some concepts. These are all Angular's Concepts. The Suite integrates with them seamlessly.
FormControl¶
A FormControl is the most basic unit inside a form which has a Value. Think of them as the leafs of the tree. They are your Text, Password inputs, etc.
FormControls have validation status and a list of errors.
HTML | |
---|---|
TypeScript | |
---|---|
The FormControl's value would be a string containing the text the user typed.
FormGroup¶
A FormGroup is a set of FormControls grouped together. The FormGroup usually represents a subset of a complete Form.
It's value is an object made from the values of all the FormControl's it is grouping.
HTML | |
---|---|
TypeScript | |
---|---|
The FormGroup's value would be an object, where each key is the FormControl's name and the value is the FromControl's value.
The FormGroup has validation status and errors, both of which are compiled from its inner controls. Meaning that, if a FormControl is invalid, the FormGroup will be invalid. This is what allows us to handle validation of an entire Form or subset of a Form in a single place.
FormArray¶
The FormArray is a collection of AbstractControl
s. An AbstractControl
is
either a FormControl, a FormGroup or a FormArray.
That means that a FormArray is a set of either FormControls, FormGroups or FormArrays.
FormArrays are used when you have a Form that allows you to "add elements" to it. For example, a Form that allows you to add as many Guests as you want and for each of them you have to fill a set of inputs.
Usually we see FormArrays of FormGroups. That's what allows you to know that the entire list is valid or not. You can also know which of the FormGroups is invalid and the errors.
HTML | |
---|---|
TypeScript | |
---|---|
The FormArray value would belike this:
Form¶
There is no class for "implementing a form". We simply use the <form>
element
in combination with a [FormGroup]
. Cause, basically a Form is just a Group of
Controls.
The cool thing about the <form>
element is that it has the (submit)
event
that we can use to know when the form has been submitted. In combination with
making the entire form a FormGroup, we can know if it is valid or not.
Suite Standard FormControls¶
Now you know the building blocks. The Suite includes a set of what we call Standard Form Controls that implement the basic HTML inputs and some more complex that we usually see when building enterprise applications.
Text FormControl¶
The text
FormControl is the replacement of the input type="text"
.
HTML | |
---|---|
Password FormControl¶
The password
FormControl is the replacement of the input type="password"
. It
includes the "toggle password visibility" feature.
HTML | |
---|---|
Other FormControls¶
Yeah that's it for now.. We are working on building more!
Custom FormGroup¶
Usually, we wanna split a huge Form into multiple Components in order to simplify it. We will quickly realize that we have no clear way of "making our component behave like a FormGroup".
So.. We could simple use an @Input() FormGroup
, but what about
formControlName
? It starts to get tricky. For that purpose the Suite includes
a FormGroupComponent
that we can use to make our component behave like a
group.
We can run the below command to generate a component which extends from
FormGroupComponent
:
Bash | |
---|---|
Then we need to initialize the group in ngOnInit
:
As you can see, the FormGroupComponent
already includes the formGroup
which
is bind properly from the caller side.
We still need to add the FormControls to it, so we do that in the OnInit.
Then, we can just use our Component as a FormGroup!
HTML | |
---|---|
Custom FormArray¶
FormArrays can be quickly created by extending the
FormArrayComponent<TControl>
class. We usually wanna use a FormGroup
as
TControl.
The base class gives us a formArray
and formControls
properties, which
contains the FormArray instance and its list of Controls casted to TControl.
This allows us to quickly build components that behave as a FormArray!
We can run the below command to generate a component which extends from
FormArrayComponent
:
Bash | |
---|---|
We need to add methods for adding and removing, and specify the array's generic constraint:
The usage would be like this:
HTML | |
---|---|
Custom FormControls¶
For developing custom FormControls, the Suite includes the
FormControlComponent
class and StandardFormControlComponent
class.
That being said, before building a FormControl please contact the Suite Team, since we may want to reuse your control. In the case you feel your control is not reusable, perhaps it should be a FormGroup instead; so talk to us and let's figure it out together!
In any case, the idea behind the FormControlComponent
is that you get a
control : FormControl
field that you need to keep up to date. The class
implements a ControlValueAccessor bind to that control.
We can run the below command to generate a component which extends from
FormControlComponent
:
Bash | |
---|---|
The schematic generates the below:
- Component that extends from
FormControlComponent
- A constant for the control's type.
- The special selector we use. i.e:
its-form-control[${TEXT_FORM_CONTROL_TYPE}]
. - An angular module which declares the component and all of its dependencies. This is for tree-shaking.
- The module also registers the component with the
FormControlRepositoryService
which is required for using the component in aDynamicFormControl
The module should look like this:
Your component should look like this:
Then we just need to set the control
's value somehow. In the case of a Text
control we just bind it to the underlying input.
HTML | |
---|---|
Once we've done this, we can use our control like so:
HTML | |
---|---|
Standard Form Controls¶
When building Standard Form Controls, meaning the controls for the framework, we can use below schematic:
Bash | |
---|---|
It is important to use the itsStandardFormField
directive on the
mat-form-field
which will give it the standard look that we want for all Suite
Controls.
Composite Form Controls¶
When building a Control with an object value, first think if it shouldn't be a FormGroup instead.
In some cases, a FormControl with an object value makes sense, like in the case of a multi-selection component, where the FormControl's value is an item (or a set of items) from the original data set.
Exposing Control to other Modules¶
When building Standard Form Controls, or any sort of reusable components we need to export it in order to be able to use it from external modules.
In the Suite Module that contains the form, we need to export
TextFormControlModule
and the TextFormControlComponent
in the
public-api.ts
file and then import it into the module of the application where
you want to use it.
Dynamic Form Control Directive¶
When building dynamic forms, it is useful to create a Form Control dynamically
on runtime. Say you have a property controlType = "text"
in a Component.
You can then use the dynamic form control like so:
HTML | |
---|---|