Dependent forms
Forms can be dependent on each other. For example, you might want to show or hide certain fields based on the value of another field above. Or show an entirely different sub-form based on a selection. Both are equally possible.
Defining dependent forms
The first design choice is to what value the final form should return, which should contain all information. This is can be done with records with optional fields or discriminated unions.
For example, consider a form where the user can select between two options, to enter information about a teacher or a student. Based on the selection, we will show a different sub-form.
First we define our data type, and the form that chooses between the two options.
For the latter, because we only have two options, we can use a bool
value for simplicity, but this could be expanded to use unions too for more options.
The StudentForm
is already prepared to work with a WebSharper.UI.Client.CheckedInput<int>
value internally which is produced by UI helpers to aid validating and parsing nubmer inputs.
Then if the value passes validators, it is safe to map it to an int
.
The next step is to take a look at the signatures of TeacherForm
and StudentForm
to see what arguments their render function takes.
For TeacherForm
it is Var<Subject>
, and for StudentForm
it is Var<CheckedInput<int>>
.
We need to create a helper union type that can switch between these two reactive vars, because to create a dependent form, we need to have a uniform input side too.
Now, we are ready to use the Form.Dependent
function to show a different sub-form based on the value of the IsTeacherForm
.
On both sub-forms, we use Form.MapRenderArgs
to unify the types of the input side, and Form.Map
to unify the types of the form result.
This sets things up well for both rendering and running the form, where the types themselves will guide writing correct code.
Using Form.Do
computation expression
Alternatively, you can use the Form.Do
computation expression to achieve the same result.
This can be more readable, especially when you have multiple dependent forms, it avoids nested lambdas, but otherwise it's syntax sugar only.
Every use of let!
will create a dependent form.
We use return!
to return a final form without an extra layer of dependent forms, as return
would only allow to return a form result value.
Rendering dependent forms
When rendering dependent forms, we can start with Forms.Render
as with other forms.
The rendering function will get a value of type Form.Dependent<_,_,_>
, which enables rendering the two sub-forms, called primary and dependent.
In the rendering function, we use dep.RenderPrimary
to render the first form, which selects between student and teacher.
Then we use dep.RenderDependent
to render the sub-form based on the selection. The submit.View.Through rvYear
is used to show validation messages for the student form's input.
Complete example
Here is now the complete example, showcasing all the elements described in this tutorial.