Build in-place editable forms comprised of fields.
An in-place editable form is a form representing an existing entity where each individual field is in "Displaying" state
initially, but can be switched to "Editing" state by clicking on it.
The updated entity is usually being validated and returned onBlur.
If you're looking for a classic form which can represent a non-existing entity (like a sign up form) and which is
comprised of editable fields, take a look at Uniform.Classic module.
Make a empty form with no fields that always successfully produces the given output.
Useful as a starting point to which you can append fields.
A value that knows how to fill a specific field with an appropriate value from values.
You shouldn't care about this type at all, it's exported so that Uniform.Classic.field can be implemented.
Define an actual field. It is not tied to a specific form yet, go and append it!
First argument is a function telling if the given value is empty.
Useful for custom field types, but if you find yourself working mostly with text fields, take a look at textField.
Second argument is where you describe how to get and set the value, and how to parse it into the output.
ageField =
Uniform.field
String.isEmpty
{ parser = Result.fromMaybe "Not an integer" String.toInt
, value = .age
, updateValue = \values age -> { values | age = age }
, state = Uniform.Displaying
, updateState = \values state -> { values | ageState = state }
}Describe how to get, set, parse the field's value and state.
parser specifies how to validate the value.
It needs a function that processes the value of the field and produces a Result of either:String describing an error,output.value specifies how to get the value and the state from values.
Most of the time it will be in a form of .fieldName.update specified how to update values with a new value and/or a new state.
Most of the time it will look like \values value -> { values | fieldName = value }Take a field and append it to the form.
userForm =
Uniform.succeed User Fields
|> Uniform.append nameField
|> Uniform.append ageFieldLots of fields, however, are just plain strings with custom validation. This alias is not mandatory to use, but can help to shorten your fields definition a bit.
It is intentional that there are no other similar aliases in the library. I encourage you to define your own aliases for your custom value types.
Define a text field. Not mandatory to use, but can help to shorten your fields definition a bit.
All it does is calling field String.isEmpty.
It is intentional that there are no other similar helpers in the library. I encourage you to implement similar helper functions for your custom value types.
All fields are required by default, but you can make them optional.
Uniform.succeed SomeOutput SomeFields
|> Uniform.append field1
|> Uniform.append (optional field2)The corresponding field in your output model must be Maybe output instead of just output.
This function allows fields to peek into other fields values.
You can use it for plenty different use cases:
values should only represent form values?
Nothing stops you from defining an extra field that you can inspect later).fieldWithComplexValidation =
Uniform.dynamicField
\values ->
Uniform.textField
{ parser = complexParser values
, ...
}Once you have your form defined and fields appended, you can now fill it with values.
If all values are properly parsed into fields, the returned output field will contain Just output, otherwise Nothing.
You can inspect individual fields from the returned fields, each one will have a type of Field.
However, I would advise not to implement your view for the form by inspecting the returned fields directly.
It is error-prone: it is easy to forget to branch on the state, or to call wrong update functions.
viewField function is a type-safe way to view fields, it should cover all your needs.
Represents a field filled with values.
value contains the "raw" value that can be displayed in a view,updateValue is a function that is usually used in an onInput event,state contains the current state of the field,updateState is a function that is usually used in onClick/onBlur events,output contains either a successfully parsed output or an error.Each field in an in-place editable form can be either Editing or Displaying.
I hope these names are obvious :) If not, submit a PR!
This represents validation errors that may happen during filling a form.
Again, naming should be obvious. If not, submit a PR!
Transform the output of the form.
This function can help you to keep forms decoupled from specific view messages:
Uniform.mapOutput SignUp userFormThe form definition is completely decoupled from its view. You are responsible for implementing views for your form; as there are no two identical forms, I don't even try to provide a "universal, configurable" solution to this problem.
However, I can provide some helpers so that it's easy to display the form's fields properly.
If these helpers don't work for you, opt-out and inspect the filled form's fields directly.
A type-safe way to view a single field from the filled form's fields.
viewNameField =
Uniform.viewField
{ viewWhenDisplaying = ...
, viewWhenEditing = ...
}
viewAgeField =
Uniform.viewField
{ viewWhenDisplaying = ...
, viewWhenEditing = ...
}
viewForm model =
let
filled =
Uniform.fill userForm model.formValues
in
Html.div
[]
[ viewNameField
, viewAgeField
]Describe how to view a form's field in a proper state.
viewWhenDisplaying is a function that is called when the field is in Displaying state.
Accepts the value to display and the makeEditable function that should be called in onClick handler like this:
viewWhenDisplaying { value, makeEditable } =
Html.div
[ Html.Events.onClick (FormUpdated makeEditable) ]
[ Html.text value ]viewWhenEditing is a function that is called when the field is in Editing state.
Accepts the value to display, the updateValue function that should be called in onInput handler,
and the finishEditing function that should be called in onBlur handler like this:
viewWhenEditing { value, updateValue, finishEditing } =
Html.input
[ Html.Events.onBlur (FormUpdated finishEditing)
, Html.Events.onInput (FormUpdated << updateValue)
, Html.Attributes.value value
, Html.Attributes.type\_ "text"
[]
Unsurprisingly, a
Formis a collection offieldswhich produces anoutputwhen filled withvalues. Of course, this does nothing by itself. It needs to have somefields!