Sorry, I wasn't trying to point our flaws in your solution. I think it illustrates that it's tricky to keep a model and an html form in sync when you update the form on every keypress: you need to be a lot more lax on invalid input than if you had a submit button, as with a traditional MVC framework: as the user types the day/month/year fields, the resulting date won't be valid until enough characters have been typed and so you need to allow your Date model to be out of sync with your y/m/d form inputs. Therefore you must keep track of both in your application state.
Submit buttons provide a best user experience for most forms anyway. But if you want to implement them you need your button's onclick callback to be able to read the state of your form inputs (not the elm way), or you must keep your form inputs in the model. Thanks Magnus for helping understand better ;) On Thursday, June 30, 2016 at 3:49:57 PM UTC+1, Robert Walter wrote: > > Well, naturally, my "solution" has some flaws, but I was trying to address > the issue you described, without adding any sophisticated validation ;) You > could still use it and just never display the default date. And if the > input is invalid, you just don't overwrite the last valid input. There are > a lot of ways how you can achieve what you want based on my suggestion. > Having said that, I'd agree with Magnus, btw.. Having three text boxes to > enter a date might not have the best UX. > > In any case, you are free to adjust your model and store three Int values > and validate them manually, of course. > > Good luck! > > On Thursday, June 30, 2016 at 4:41:35 PM UTC+2, Max Froumentin wrote: >> >> Thanks Robert, that helps a lot. >> That doesn't always work though: the date as a string can be parsed >> wrongly (eg if you put 2 in the year it'll set the date to 2 jan 2001), or >> if you put a bad year, date or month. If you delete that 2, the date >> remains the same, etc. >> >> Ideally I'd like no date default (this is for a date of birth, so it >> wouldn't make sense). In that case you can't really store a Maybe Date in >> your model, as any partially correct date will result in Nothing and you'll >> lose the correct fields. >> >> So I think that it's probably best to have 3 Ints in the model and parse >> to a Date as needed. >> >> On Thursday, June 30, 2016 at 11:04:51 AM UTC+1, Robert Walter wrote: >>> >>> You could create a new date out of the old date plus the element that >>> changed due to input. I'm new to Elm, so my solution is not pretty, but >>> maybe it helps get on the right track. You also might want to check out the >>> date >>> extra package >>> <http://package.elm-lang.org/packages/rluiten/elm-date-extra/7.0.0>. >>> >>> Something like this (not tested): >>> >>> import Html exposing(..) >>> import Html.App as Html >>> import Html.Attributes exposing(..) >>> import Html.Events exposing (onInput) >>> import Date exposing(..) >>> import Result exposing(..) >>> >>> type alias Model = Result String Date >>> >>> type Msg = >>> YearChange String >>> | MonthChange String >>> | DayChange String >>> >>> main = Html.beginnerProgram >>> { model = default >>> , update = update >>> , view = view >>> } >>> >>> default = Date.fromString "1990-01-01" >>> >>> update : Msg -> Model -> Model >>> update msg model = >>> let >>> maybeModel = Result.toMaybe model >>> yearCur = resolveMaybe maybeModel year 90 |> toString >>> monthCur = resolveMaybe maybeModel month Jan |> toString >>> dayCur = resolveMaybe maybeModel day 1 |> toString >>> in >>> case msg of >>> YearChange yearNew -> >>> newDate (yearNew, monthCur, dayCur) >>> MonthChange monthNew -> >>> newDate (yearCur, monthNew, dayCur) >>> DayChange dayNew -> >>> newDate (yearCur, monthCur, dayNew) >>> >>> resolveMaybe : Maybe Date -> (Date -> a) -> a -> a >>> resolveMaybe maybeModel extractor default = >>> case maybeModel of >>> Nothing -> default >>> Just val -> extractor val >>> >>> newDate : (String, String, String) -> Model >>> newDate (y,m,d) = >>> Date.fromString >>> <| dateString (y, m, d) >>> >>> dateString : (String, String, String) -> String >>> dateString (y,m,d) = >>> toString y ++ "/" ++ m ++ "/" ++ d >>> >>> view : Model -> Html Msg >>> view model = >>> let >>> maybeModel = Result.toMaybe model >>> yearCur = resolveMaybe maybeModel year 90 |> toString >>> monthCur = resolveMaybe maybeModel month Jan |> toString >>> dayCur = resolveMaybe maybeModel day 1 |> toString >>> in >>> div[] >>> [ input [type' "number", placeholder "1990", onInput YearChange ] [ ] >>> , input [type' "number", placeholder "1", onInput MonthChange ] [ ] >>> , input [type' "number", placeholder "1", onInput DayChange ] [ ] >>> , div[] [text (dateString (toString yearCur, toString monthCur, >>> toString dayCur)) ] >>> ] >>> >>> >>> >>> On Thursday, June 30, 2016 at 10:30:13 AM UTC+2, Max Froumentin wrote: >>>> >>>> Hi there, >>>> I'm writing a web app with a Date in the model, which I would like to >>>> map to 3 input (type=text) fields, for day, month and year. >>>> I'm stuck as to how to modify the model's date when the user changes >>>> one of the fields. >>>> >>>> The Date type doesn't seem to have a way to modify a single field, and >>>> I'm not sure how you collect the three input values in one update. >>>> >>>> Am I missing something, or are models expected to map 1-to-1 with form >>>> elements? >>>> >>> -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
