Last active
October 5, 2016 01:28
-
-
Save ericgj/7adf98715af89aebd1a2dc73433f5094 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Html exposing (Html, div, button, text) | |
import Html.Attributes as Attr | |
import Html.Events as Evt | |
import Html.App exposing (beginnerProgram) | |
import Html.Events exposing (onClick) | |
import Json.Decode as Json | |
import String | |
sample : Person | |
sample = { name = "Thor", age = 54, password = "#NDkds_(", optional = Nothing } | |
main : Program Never | |
main = | |
beginnerProgram { model = init (Just sample), view = view, update = update } | |
type alias Person = | |
{ name : String, age : Int, password : String, optional: Maybe String } | |
type alias Model = | |
{ person : Maybe Person | |
, personAge : Result (String,String) Int | |
, personName : Result (String,String) String | |
, personPassword : Result (String,String) String | |
, personOptional : Result (String,String) (Maybe String) | |
, dirty : Bool | |
} | |
init : Maybe Person -> Model | |
init mperson = | |
{ person = mperson | |
, personAge = | |
Maybe.map .age mperson | |
|> Result.fromMaybe ("Please enter your age","") | |
, personName = | |
Maybe.map .name mperson | |
|> Result.fromMaybe ("Please enter your name","") | |
, personPassword = | |
Maybe.map .password mperson | |
|> Result.fromMaybe ("Please enter your password","") | |
, personOptional = | |
Maybe.map .optional mperson | |
|> Result.fromMaybe ("Comments if you like","") | |
, dirty = False | |
} | |
onBlurWithValue tagger = | |
Evt.on "blur" (Json.map tagger Evt.targetValue) | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ div [] | |
[ Html.input | |
[ Attr.placeholder "age" | |
, Attr.type' "number" | |
, Attr.value (valueFromResult toString model.personAge) | |
, onBlurWithValue (validate okAge >> UpdateAge) | |
] | |
[] | |
, Html.text <| resultToString model.personAge | |
] | |
, div [] | |
[ Html.input | |
[ Attr.placeholder "name" | |
, Attr.value (valueFromResult identity model.personName) | |
, onBlurWithValue (validate okName >> UpdateName) | |
] | |
[] | |
, Html.text <| resultToString model.personName | |
] | |
, div [] | |
[ Html.input | |
[ Attr.placeholder "password" | |
, Attr.type' "password" | |
, Attr.value (valueFromResult identity model.personPassword) | |
, onBlurWithValue (validate okPassword >> UpdatePassword) | |
] | |
[] | |
, Html.text <| resultToString model.personPassword | |
] | |
, div [] | |
[ Html.input | |
[ Attr.placeholder "optional" | |
, Attr.value (valueFromResult (Maybe.withDefault "") model.personOptional) | |
, onBlurWithValue (emptyToResult >> UpdateOptional) | |
] | |
[] | |
, Html.text <| resultToString model.personOptional | |
] | |
, button | |
[ Attr.disabled (model.person == Nothing) | |
, Evt.onClick SavePerson | |
] | |
[ text "Save me" ] | |
, div [ Attr.style [("color","red")] ] | |
[ (case model.person of | |
Just person -> | |
Html.text (toString person) | |
_ -> | |
Html.text "Couldn't save you yet" | |
) | |
] | |
] | |
type Msg | |
= UpdateAge (Result (String,String) Int) | |
| UpdateName (Result (String,String) String) | |
| UpdatePassword (Result (String,String) String) | |
| UpdateOptional (Result (String,String) (Maybe String)) | |
| SavePerson | |
update : | |
Msg | |
-> Model | |
-> Model | |
update msg model = | |
case msg of | |
UpdateAge age -> | |
let newmodel = | |
{ model | dirty = True, personAge = age } | |
in | |
{ newmodel | person = createPerson newmodel } | |
UpdateName name -> | |
let newmodel = | |
{ model | dirty = True, personName = name } | |
in | |
{ newmodel | person = createPerson newmodel } | |
UpdatePassword pw -> | |
let newmodel = | |
{ model | dirty = True, personPassword = pw } | |
in | |
{ newmodel | person = createPerson newmodel } | |
UpdateOptional opt -> | |
let newmodel = | |
{ model | dirty = True, personOptional = opt } | |
in | |
{ newmodel | person = createPerson newmodel } | |
SavePerson -> | |
{ model | dirty = False } | |
createPerson : Model -> Maybe Person | |
createPerson model = | |
Result.map4 Person | |
model.personName | |
model.personAge | |
model.personPassword | |
model.personOptional | |
|> Result.toMaybe | |
resultToString : Result (String,String) b -> String | |
resultToString result = | |
case result of | |
Ok _ -> | |
"All good" | |
Err (msg, _) -> | |
msg | |
isErr : Result a b -> Bool | |
isErr result = | |
case result of | |
Err _ -> | |
True | |
_ -> | |
False | |
-- always Ok, convert empty strings to Nothing | |
emptyToResult : String -> Result (String,String) (Maybe String) | |
emptyToResult s = | |
if String.length s == 0 then Ok Nothing | |
else Ok (Just s) | |
-- Get either the Ok value (converted to String), | |
-- or the last input string from the result | |
valueFromResult : (a -> String) -> Result (String,String) a -> String | |
valueFromResult formatter r = | |
case r of | |
Ok a -> formatter a | |
Err (_,last) -> last | |
-- Put the last input string into the result | |
validate : | |
(String -> Result String a) -> | |
String -> | |
Result (String,String) a | |
validate func str = | |
(func str) |> Result.formatError (\err -> (err, str)) | |
okName : String -> Result String String | |
okName name = | |
if String.length name > 3 then | |
Ok name | |
else | |
Err "Name must be more than 3 characters." | |
okAge : String -> Result String Int | |
okAge age = | |
Result.andThen | |
(String.toInt age | |
|> Result.formatError (\s -> "You must provide an age.") | |
) | |
(\age -> | |
if age > 10 then | |
Ok age | |
else | |
Err "Age must be greater than 10." | |
) | |
okPassword : String -> Result String String | |
okPassword pw = | |
if String.length pw > 7 then | |
Ok pw | |
else | |
Err "Name must be more than 7 characters." | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment