Build composable forms with your own custom fields.
This is the base of the composable-form
package. It implements a composable Form
type that is not tied to any particular field
.
In order to understand this module, you should be familar with the basic Form module
first.
A Form
that can contain any type of field
.
Say you need to use a type of field that is not implemented in the the basic Form module
.
The recommended way of doing this is to start your own Form
module using field
and
custom
to define new types of fields.
For instance, you could start your own MyProject.Form
module like this:
import Form.Base as Base
type alias Form values output =
Base.Form values output (Field values)
type Field values
= None
succeed : output -> Form values output
succeed =
Base.succeed
-- Other useful operations you will probably want to use,
-- like append, andThen...
Notice that we could avoid redefining succeed
, append
, and others, but that would force us to
import Form.Base
every time we needed to use those operations with our brand new form.
field : { isEmpty : input -> Basics.Bool } -> (Form.Field.Field attributes input values -> field) -> FieldConfig attributes input values output -> Form values output field
Create functions that build forms which contain a single field with an API that is similar to
the basic Form
module.
This function is meant to be partially applied, providing only the two first parameters to
obtain a function that expects the configuration for a particular type of field. See
FieldConfig
.
For this, you only need to provide:
input
of the field tells whether it is empty or not.Field
to your own specific field
type.For example, Form.textField
could be implemented like this:
textField :
{ parser : String -> Result String output
, value : values -> String
, update : String -> values -> values
, attributes : TextField.Attributes
}
-> Form values output
textField =
Base.field { isEmpty = String.isEmpty } (Text TextRaw)
Notice how the configuration record in textField
is a FieldConfig
.
Note: You can use TextField.form
,
SelectField.form
, and others to build fields that are already
present in Form
.
{ parser : input -> Result String output
, value : values -> input
, update : input -> values -> values
, error : values -> Maybe String
, attributes : attrs
}
Most form fields require configuration! FieldConfig
allows you to specify how a
concrete field is validated and updated, alongside its attributes:
parser
must be a function that validates the input
of the field and produces a Result
of either:output
String
describing a problemvalue
defines how the value of the field is obtained from the form values
.update
defines how the current form values
should be updated with a new field value.error
defines how to obtain a potential external error from the form values
.
This can be useful to include server-side errors in your form!attributes
represent the attributes of the field.custom : (values -> CustomField output field) -> Form values output field
Create a custom field with total freedom.
You only need to provide a function that given some values
produces a FilledField
.
You can check the custom fields example for some inspiration.
{ state : field
, result : Result ( Form.Error.Error
, List Form.Error.Error ) output
, isEmpty : Basics.Bool
}
Represents a custom field on a form that has been filled with values.
It contains:
succeed : output -> Form values output field
Like Form.succeed
but not tied to a particular type of field
.
append : Form values a field -> Form values (a -> b) field -> Form values b field
Like Form.append
but not tied to a particular type of field
.
andThen : (a -> Form values b field) -> Form values a field -> Form values b field
Like Form.andThen
but not tied to a particular type of field
.
optional : Form values output field -> Form values (Maybe output) field
Like Form.optional
but not tied to a particular type of field
.
disable : Form values output field -> Form values output field
Like Form.disable
but not tied to a particular type of field
.
meta : (values -> Form values output field) -> Form values output field
Like Form.meta
but not tied to a particular type of field
.
map : (a -> b) -> Form values a field -> Form values b field
Like Form.map
but not tied to a particular type of field
.
mapValues : (a -> b) -> Form b output field -> Form a output field
Apply a function to the input values
of the form.
mapField : (a -> b) -> Form values output a -> Form values output b
Apply a function to each form field
.
{ fields : List (FilledField field)
, result : Result ( Form.Error.Error
, List Form.Error.Error ) output
, isEmpty : Basics.Bool
}
Represents a filled form.
You can obtain this by using fill
.
{ state : field
, error : Maybe Form.Error.Error
, isDisabled : Basics.Bool
}
Represents a filled field.
fill : Form values output field -> values -> FilledForm output field
Like Form.fill
but not tied to a particular type of field
.