bgrosse-midokura / composable-form / Form.View

This module provides helpers to render a Form.

If you just want to quickly render a Form as HTML, take a look at asHtml. If you need more control, see custom and htmlViewConfig.

Note: If you are implementing your own custom fields using Form.Base then you cannot use this module. You should use Form.Base.fill to write custom view code. Take a look at the source code of this module for inspiration.

Model


type alias Model values =
{ values : values
, state : State
, errorTracking : ErrorTracking 
}

This type gathers the values of the form, with some exposed state and internal view state that tracks which fields should show validation errors.


type State
    = Idle
    | Loading
    | Error String
    | Success String

Represents the state of the form.

You can change it at will from your update function. For example, you can set the state to Loading if submitting the form fires a remote action, or you can set it to Error when such action fails.

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        FormChanged newModel ->
            ( { newModel | state = FormView.Idle }, Cmd.none )

        SignUp email password ->
            ( { model | state = FormView.Loading }
            , User.signUp email password
                |> Task.attempt SignupTried
            )

        SignupTried (Ok user) ->
            ( { model | state = FormView.Success "You are now registered successfully :)" }, Route.navigate (Route.Profile user.slug) )

        SignupTried (Err error) ->
            ( { model | state = FormView.Error error }, Cmd.none )

idle : values -> Model values

Create a Model representing an idle form.

You just need to provide the initial values of the form.

Configuration


type alias ViewConfig values msg =
{ onChange : Model values -> msg
, action : String
, loading : String
, validation : Validation 
}

This allows you to configure the view output.


type Validation
    = ValidateOnSubmit
    | ValidateOnBlur

The validation strategy.

Basic HTML

asHtml : ViewConfig values msg -> Form values msg -> Model values -> Html msg

Render a form as HTML!

You could use it like this:

FormView.asHtml
    { onChange = FormChanged
    , action = "Log in"
    , loading = "Logging in..."
    , validation = FormView.ValidateOnSubmit
    }
    loginForm
    model

And here is an example of the produced HTML:

<form class="elm-form">
   <label class="elm-form-field">
       <div class="elm-form-label">E-Mail</div>
       <input type="email" value="some@value.com" placeholder="Type your e-mail...">
   </label>
   <label class="elm-form-field elm-form-field-error">
       <div class="elm-form-label">Password</div>
       <input type="password" value="" placeholder="Type your password...">
       <div class="elm-form-error">This field is required</div>
   </label>
   <button type="submit">Log in</button>
</form>

You can use the different CSS classes to style your forms as you please.

If you need more control over the produced HTML, use custom to provide your own view functions. To customize the behavior of individual view functions, see htmlViewConfig.

htmlViewConfig : CustomConfig msg (Html msg)

Default CustomConfig implementation for HTML output.

You can update a subset of the CustomConfig fields to implement a view function that overrides the behavior of asHtml. For example:

htmlView : ViewConfig values msg -> Form values msg -> Model values -> Html msg
htmlView =
    custom
        { htmlViewConfig
            | selectField = mySelectField
            , radioField = myRadioField
        }

In fact, asHtml is just implemented as:

asHtml : ViewConfig values msg -> Form values msg -> Model values -> Html msg
asHtml =
    custom htmlViewConfig

Custom

custom : CustomConfig msg element -> ViewConfig values msg -> Form values msg -> Model values -> element

Create a custom view function.

You need to provide a set of functions to render each field, and a function to put them all together in a form, see CustomConfig.

This can be used to create view functions that are compatible with style-elements, elm-mdl, elm-css, etc. You could even use it to transform forms into a String or Json.Value! Take a look at the different view modules in the examples directory as you might find an implementation that works for you.

Once you provide a CustomConfig, you get a view function that supports a ViewConfig.


type alias CustomConfig msg element =
{ form : FormConfig msg element -> element
, textField : TextFieldConfig msg -> element
, emailField : TextFieldConfig msg -> element
, passwordField : TextFieldConfig msg -> element
, textareaField : TextFieldConfig msg -> element
, searchField : TextFieldConfig msg -> element
, numberField : NumberFieldConfig msg -> element
, rangeField : RangeFieldConfig msg -> element
, checkboxField : CheckboxFieldConfig msg -> element
, radioField : RadioFieldConfig msg -> element
, selectField : SelectFieldConfig msg -> element
, group : List element -> element
, section : String -> List element -> element
, formList : FormListConfig msg element -> element
, formListItem : FormListItemConfig msg element -> element 
}

The configuration needed to create a custom view function.

It needs functions to render each of the supported Form fields, a function to render a group of fields, and a function to wrap the fields together in a form.


type alias FormConfig msg element =
{ onSubmit : Maybe msg
, state : State
, action : String
, loading : String
, fields : List element 
}

Describes how a form should be rendered.


type alias TextFieldConfig msg =
{ onChange : String -> msg
, onBlur : Maybe msg
, disabled : Basics.Bool
, value : String
, error : Maybe Form.Error.Error
, showError : Basics.Bool
, attributes : Form.Base.TextField.Attributes 
}

Describes how a text field should be rendered.


type alias NumberFieldConfig msg =
{ onChange : String -> msg
, onBlur : Maybe msg
, disabled : Basics.Bool
, value : String
, error : Maybe Form.Error.Error
, showError : Basics.Bool
, attributes : Form.Base.NumberField.Attributes Basics.Float 
}

Describes how a number field should be rendered.

The other record fields are described in TextFieldConfig.


type alias RangeFieldConfig msg =
{ onChange : Maybe Basics.Float -> msg
, onBlur : Maybe msg
, disabled : Basics.Bool
, value : Maybe Basics.Float
, error : Maybe Form.Error.Error
, showError : Basics.Bool
, attributes : Form.Base.RangeField.Attributes Basics.Float 
}

Describes how a range field should be rendered.

The other record fields are described in TextFieldConfig.


type alias CheckboxFieldConfig msg =
{ onChange : Basics.Bool -> msg
, onBlur : Maybe msg
, disabled : Basics.Bool
, value : Basics.Bool
, error : Maybe Form.Error.Error
, showError : Basics.Bool
, attributes : Form.Base.CheckboxField.Attributes 
}

Describes how a checkbox field should be rendered.

This is basically a TextFieldConfig, but its attributes are CheckboxField.Attributes.


type alias RadioFieldConfig msg =
{ onChange : String -> msg
, onBlur : Maybe msg
, disabled : Basics.Bool
, value : String
, error : Maybe Form.Error.Error
, showError : Basics.Bool
, attributes : Form.Base.RadioField.Attributes 
}

Describes how a radio field should be rendered.

This is basically a TextFieldConfig, but its attributes are RadioField.Attributes.


type alias SelectFieldConfig msg =
{ onChange : String -> msg
, onBlur : Maybe msg
, disabled : Basics.Bool
, value : String
, error : Maybe Form.Error.Error
, showError : Basics.Bool
, attributes : Form.Base.SelectField.Attributes 
}

Describes how a select field should be rendered.

This is basically a TextFieldConfig, but its attributes are SelectField.Attributes.


type alias FormListConfig msg element =
{ forms : List element
, label : String
, add : Maybe { action : () -> msg
, label : String }
, disabled : Basics.Bool 
}

Describes how a form list should be rendered.


type alias FormListItemConfig msg element =
{ fields : List element
, delete : Maybe { action : () -> msg
, label : String }
, disabled : Basics.Bool 
}

Describes how an item in a form list should be rendered.