diff --git a/examples/smoothies/app/Route/SmoothieId_/Edit.elm b/examples/smoothies/app/Route/SmoothieId_/Edit.elm index 0a641125..f20d5ea7 100644 --- a/examples/smoothies/app/Route/SmoothieId_/Edit.elm +++ b/examples/smoothies/app/Route/SmoothieId_/Edit.elm @@ -273,6 +273,7 @@ form = |> FormParser.field "price" (Field.int { invalid = \_ -> "Invalid int" } |> Field.required "Required" + |> Field.withMin (Form.Value.int 0) |> Field.withInitialValue (\{ smoothie } -> Form.Value.int smoothie.price) ) |> FormParser.field "imageUrl" diff --git a/src/Pages/Field.elm b/src/Pages/Field.elm index 68112fb7..811d7f7e 100644 --- a/src/Pages/Field.elm +++ b/src/Pages/Field.elm @@ -1,4 +1,7 @@ -module Pages.Field exposing (Field(..), FieldInfo, No(..), Yes(..), checkbox, exactValue, int, required, text, withClientValidation, withInitialValue, select) +module Pages.Field exposing + ( Field(..), FieldInfo, No(..), Yes(..), checkbox, exactValue, int, required, text, withClientValidation, withInitialValue, select + , withMax, withMin, withStep + ) {-| @@ -280,7 +283,7 @@ int toError = ( Nothing, [ toError.invalid string ] ) , properties = [] } - (FieldRenderer.Input FieldRenderer.Text) + (FieldRenderer.Input FieldRenderer.Number) {-| -} @@ -319,3 +322,32 @@ withInitialValue toInitialValue (Field field kind) = Just (toInitialValue >> Form.Value.toString) } kind + + + +-- Input Properties + + +{-| -} +withMin : Form.Value.Value valueType -> Field msg error value view { constraints | min : valueType } -> Field msg error value view constraints +withMin min field = + withStringProperty ( "min", Form.Value.toString min ) field + + +{-| -} +withMax : Form.Value.Value valueType -> Field msg error value view { constraints | max : valueType } -> Field msg error value view constraints +withMax max field = + withStringProperty ( "max", Form.Value.toString max ) field + + +{-| -} +withStep : Form.Value.Value valueType -> Field msg error value view { constraints | step : valueType } -> Field msg error value view constraints +withStep max field = + withStringProperty ( "step", Form.Value.toString max ) field + + +withStringProperty : ( String, String ) -> Field error parsed data kind constraints1 -> Field error parsed data kind constraints2 +withStringProperty ( key, value ) (Field field kind) = + Field + { field | properties = ( key, Encode.string value ) :: field.properties } + kind diff --git a/src/Pages/FieldRenderer.elm b/src/Pages/FieldRenderer.elm index d7699532..32c5285d 100644 --- a/src/Pages/FieldRenderer.elm +++ b/src/Pages/FieldRenderer.elm @@ -4,11 +4,60 @@ module Pages.FieldRenderer exposing (..) import Html exposing (Html) import Html.Attributes as Attr +import Json.Encode as Encode type InputType = Text + | Number + | Range + | Radio + -- TODO should submit be a special type, or an Input type? + -- TODO have an option for a submit with a name/value? + | Date | Checkbox + | Tel + | Search + | Password + | Email + | Url + + +inputTypeToString : InputType -> String +inputTypeToString inputType = + case inputType of + Text -> + "text" + + Number -> + "number" + + Range -> + "range" + + Radio -> + "radio" + + Date -> + "date" + + Checkbox -> + "checkbox" + + Tel -> + "tel" + + Search -> + "search" + + Password -> + "password" + + Email -> + "email" + + Url -> + "url" type Input @@ -26,31 +75,28 @@ input : { input | value : Maybe String , name : String - , kind : Input + , kind : ( Input, List ( String, Encode.Value ) ) } -> Html msg input attrs rawField = case rawField.kind of - Input inputType -> - case inputType of - Text -> - Html.input - (attrs - ++ [ Attr.value (rawField.value |> Maybe.withDefault "") -- TODO is this an okay default? - , Attr.name rawField.name - ] - ) - [] + ( Input inputType, properties ) -> + Html.input + (attrs + ++ toHtmlProperties properties + ++ [ (case inputType of + Checkbox -> + Attr.checked ((rawField.value |> Maybe.withDefault "") == "on") - Checkbox -> - Html.input - (attrs - ++ [ Attr.checked ((rawField.value |> Maybe.withDefault "") == "on") - , Attr.name rawField.name - , Attr.type_ "checkbox" - ] - ) - [] + _ -> + Attr.value (rawField.value |> Maybe.withDefault "") + -- TODO is this an okay default? + ) + , Attr.name rawField.name + , inputType |> inputTypeToString |> Attr.type_ + ] + ) + [] {-| -} @@ -67,13 +113,13 @@ select : { input | value : Maybe String , name : String - , kind : Select parsed + , kind : ( Select parsed, List ( String, Encode.Value ) ) } -> Html msg select selectAttrs enumToOption rawField = let (Select parseValue possibleValues) = - rawField.kind + rawField.kind |> Tuple.first in Html.select (selectAttrs @@ -104,3 +150,12 @@ select selectAttrs enumToOption rawField = Nothing ) ) + + +toHtmlProperties : List ( String, Encode.Value ) -> List (Html.Attribute msg) +toHtmlProperties properties = + properties + |> List.map + (\( key, value ) -> + Attr.property key value + ) diff --git a/src/Pages/FormParser.elm b/src/Pages/FormParser.elm index 6cbbf5d5..dc54429f 100644 --- a/src/Pages/FormParser.elm +++ b/src/Pages/FormParser.elm @@ -11,6 +11,7 @@ import Dict.Extra import Html exposing (Html) import Html.Attributes as Attr import Html.Lazy +import Json.Encode as Encode import Pages.Field as Field exposing (Field(..)) import Pages.FieldRenderer import Pages.Form as Form @@ -103,14 +104,14 @@ field name (Field fieldParser kind) (CombinedParser definitions parseFn toInitia { name = name , value = Just info.value , status = info.status - , kind = kind + , kind = ( kind, fieldParser.properties ) } Nothing -> { name = name , value = Maybe.map2 (|>) maybeData fieldParser.initialValue , status = Form.NotVisited - , kind = kind + , kind = ( kind, fieldParser.properties ) } myFn : @@ -192,14 +193,14 @@ hiddenField name (Field fieldParser kind) (CombinedParser definitions parseFn to { name = name , value = Just info.value , status = info.status - , kind = () + , kind = ( (), [] ) } Nothing -> { name = name , value = Maybe.map2 (|>) maybeData fieldParser.initialValue , status = Form.NotVisited - , kind = () + , kind = ( (), [] ) } myFn : @@ -276,14 +277,14 @@ hiddenKind ( name, value ) error_ (CombinedParser definitions parseFn toInitialV { name = name , value = Just info.value , status = info.status - , kind = () + , kind = ( (), [] ) } Nothing -> { name = name , value = Maybe.map2 (|>) maybeData fieldParser.initialValue , status = Form.NotVisited - , kind = () + , kind = ( (), [] ) } myFn : @@ -795,7 +796,7 @@ type alias RawField kind = { name : String , value : Maybe String , status : Form.FieldStatus - , kind : kind + , kind : ( kind, List ( String, Encode.Value ) ) }