maca/form-toolkit/1.0.2

NOTE: the latest version is 2.0.0

FormToolkit.View

View

type View id msg

A view is a way to configure the generated markup for an Field or group of fields.

fromField : (Msg id -> msg) -> Field id -> View id msg

Construct a view from an Field.

view : Html (Never -> a)
view =
    Field.group []
        [ Field.text [ Field.label "First Name" ]
        , Field.text [ Field.label "Last Name" ]
        ]
        |> View.fromField (always never)
        |> View.toHtml
toHtml : View id msg -> Html msg

Render a view

partial : id -> View id msg -> Maybe (View id msg)

A partial view referenced by identifier. Maybe you want to render segments of the same form in different UI sections.

Field.group []
    [ Field.text
        [ Field.identifier "FirstName"
        , Field.label "First Name"
        ]
    , Field.text
        [ Field.identifier "LastName"
        , Field.label "Last Name"
        ]
    ]
    |> View.fromField (always never)
    |> View.partial "FirstName"
    == Just
        (Field.text
            [ Field.identifier "FirstName"
            , Field.label "First Name"
            ]
        )

View customizations

customizeErrors : (FieldAttributes id -> String) -> View id msg -> View id msg

Customizes how the error messages are displayed, to be used for i18n errors. The function receives field attributes including all errors for the field. It's possible to override error messages for all fields, individual fields, or fields of a certain type.

See FieldAttributes for all the available field attributes.

type Fields
    = Name
    | Temperature
    | Flavour


view : View Fields val ()
view =
    Field.group []
        [ Field.text
            [ Field.label "Name"
            , Field.identifier Name
            , Field.required
            ]
        , Field.text
            [ Field.label "Temperature"
            , Field.identifier Temperature
            , Field.min 20
            , Field.max 35
            , Field.required
            ]
        , Field.select
            [ Field.label "Flavour"
            , Field.identifier Flavour
            , Field.required
            , Field.options
                [ ( "Banana", Value.string "banana" )
                , ( "Strawbery", Value.string "strawberry" )
                , ( "Chocolate", Value.string "chocolate" )
                ]
            ]
        ]
        |> View.fromField (always ())
        |> View.customizeErrors
            (\attributes ->
                let
                    toString =
                        Value.toString >> Maybe.withDefault ""


                    errorToString error =
                        case ( attributes.inputType, error ) of
                            ( _, ValueTooLarge _ data ) ->
                                toString data.max ++ " is too high"


                            ( _, ValueTooSmall _ data ) ->
                                toString data.min ++ " is too low"


                            ( _, ValueNotInRange _ data ) ->
                                "Make it in between " ++ toString data.min ++ " and " ++ toString data.max


                            ( Select, IsBlank _ ) ->
                                "Make up your mind"


                            ( _, IsBlank (Just Name) ) ->
                                "Who are you?"


                            ( _, IsBlank _ ) ->
                                "You forgot to fill in this"


                            ( _, CustomError _ message ) ->
                                message


                            _ ->
                                "Humm...?"
                in
                attributes.errors
                    |> List.map errorToString
                    |> String.join ", "
            )
( { labelHtml : List (Attribute msg) -> Html msg
, fieldHtml : List (Attribute msg) -> Html msg
, hintHtml : List (Attribute msg) -> Html msg
, errors : List String
, class : String
, attributes : FieldAttributes id
, inputOnChange :
-> { selectionStart : Int
, selectionEnd : Int
}
-> msg
, inputOnCheck : Bool -> msg
, inputOnBlur : msg
, inputOnFocus : msg
}
-> Maybe (Html msg)
)
-> View id msg
-> View id msg

Provide a function to override the rendering of a field.

The function receives a configuration record with pre-rendered HTML elements and field attributes, and should return Just (Html msg) for custom rendering or Nothing to use the default rendering.

The labelHtml, fieldHtml, and hintHtml functions take a list of Html.Attribute msg to allow customization of the rendered elements.

Use attributes to access field properties like identifier for pattern matching on specific fields. See FieldAttributes for all the avaiable field attributes.

The example below shows custom rendering for a specific field identifier:

view : View id val ()
view =
    Field.text
        [ Field.label "Name"
        , Field.identifier MyField
        ]
        |> View.fromField (always ())
        |> customizeFields
            (\{ attributes, labelHtml, fieldHtml, hintHtml, errors } ->
                case attributes.identifier of
                    Just MyField ->
                        -- Custom rendering for MyField
                        Just
                            (Html.div
                                [ Attributes.class "field" ]
                                [ labelHtml [ Attributes.class "custom-label" ]
                                , Html.div
                                    [ Attributes.class "input-wrapper" ]
                                    [ fieldHtml []
                                    , hintHtml []
                                    ]
                                ]
                            )


                    _ ->
                        -- Use default rendering for other fields
                        Nothing
            )
( { legendText : Maybe String
, fields : List (Html msg)
, identifier : Maybe id
, errors : List String
, class : String
}
-> Html msg
)
-> View id msg
-> View id msg

Provide a function to customize the rendering of a group of fields.

view : View id val ()
view =
    Field.group []
        [ Field.text [ Field.label "Name" ]
        , Field.text [ Field.label "Last Name" ]
        ]
        |> View.fromField (always ())
        |> customizeField
            (\{ fields, legendText } ->
                Html.fieldset
                    [ Html.Attribute.class "field-group" ]
                    ((case legendText of
                        Just str ->
                            Html.legend [] [ Html.text str ]


                        Nothing ->
                            Html.text ""
                     )
                        :: fields
                    )
            )
( { legendText : Maybe String
, fields : List (Html msg)
, addFieldsButton : List (Attribute msg) -> Html msg
, errors : List String
, class : String
, identifier : Maybe id
, addFieldsButtonOnClick : Maybe msg
, addFieldsButtonCopy : String
}
-> Html msg
)
-> View id msg
-> View id msg

Customize the positioning, and appearance of each of the inputs of a repeatable group of inputs and the and the button to add new inputs.

The addFieldsButton function takes a list of Html.Attribute msg to allow customization of the button element.

To customize the template used to add a new input see customizeRepeatingFieldTemplates.

view : View String val ()
view =
    Field.repeatable [ Field.identifier "People" ]
        (Field.group []
            [ [ Field.text [ Field.label "Name" ]
              , Field.text [ Field.label "Last Name" ]
              ]
            ]
        )
        []
        |> View.fromField (always ())
        |> customizeRepeatableFields
            (\{ legendText, fields, addFieldsButton } ->
                Html.fieldset []
                    [ case legendText of
                        Just str ->
                            Html.legend [] [ Html.text str ]


                        Nothing ->
                            Html.text ""
                    , Html.div [] fields
                    , addFieldsButton []
                    ]
            )
( { fieldHtml : Html msg
, removeFieldsButton : List (Attribute msg) -> Html msg
, identifier : Maybe id
, index : Int
, removeFieldsButtonOnClick : Maybe msg
, removeFieldsButtonCopy : String
}
-> Html msg
)
-> View id msg
-> View id msg

Customize the rendering of each of the elements of a repeatable group of inputs.

The removeFieldsButton function takes a list of Html.Attribute msg to allow customization of the button element.

To customize the group of inputs see customizeRepeatableFields.

view : View String val ()
view =
    Field.repeatable [ Field.identifier "People" ]
        (Field.group []
            [ [ Field.text [ Field.label "Name" ]
              , Field.text [ Field.label "Last Name" ]
              ]
            ]
        )
        []
        |> View.fromField (always ())
        |> customizeRepeatingFieldTemplates
            (\{ fieldHtml, removeFieldsButton } ->
                Html.div
                    [ Attributes.class "group-repeat" ]
                    [ fieldHtml, removeFieldsButton [] ]
            )

Field attributes

type alias FieldAttributes id =
{ fieldType : FieldType
, name : Maybe String
, value : Value
, isRequired : Bool
, label : Maybe String
, placeholder : Maybe String
, hint : Maybe String
, min : Value
, max : Value
, step : Value
, autogrow : Bool
, options : List ( String, Value )
, identifier : Maybe id
, status : Status
, repeatableMin : Int
, repeatableMax : Maybe Int
, addFieldsButtonCopy : String
, removeFieldsButtonCopy : String
, errors : List (Error id)
, classList : List String
, selectionStart : Int
, selectionEnd : Int
, disabled : Bool
, hidden : Bool
, pattern : List MaskToken
}
= Text
| TextArea
| Email
| Password
| StrictAutocomplete
| Integer
| Float
| Month
| Date
| LocalDatetime
| Select
| Radio
| Checkbox
| Group
| Repeatable
type Status
= Pristine
| Focused
| Editing
| Touched