Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
|
wiki2:elm-programming [2020/05/13 16:46] alfred [Decoders] |
wiki2:elm-programming [2021/05/02 10:06] (actual) |
||
|---|---|---|---|
| Línea 42: | Línea 42: | ||
| - | ===== Send inner messages ===== | ||
| - | ==== Commands and messages ==== | + | ===== Commands and messages ===== |
| - | Messages are signals that Elm creates when something happens. | + | Messages are generated by the View in response to the user's interaction. Messages represent user requests to alter the application's state. |
| Commands (''Cmd'') are something you want the system do, when it is done it will produce a Message. | Commands (''Cmd'') are something you want the system do, when it is done it will produce a Message. | ||
| - | If something waits for a Command but you do not have any Command to apply you can send ''Cmd.none''. | + | Messages and commands are not synonymous. Messages represent the communication between an end user and the application while commands represent how an Elm application communicates with other entities. A command is triggered in response to a message. |
| - | + | ||
| - | + | ||
| - | ==== Commands ==== | + | |
| - | + | ||
| + | The type ''Message'' is defined my the user, sometimes called ''Msg''. Again, it's upon the user. | ||
| ==== To trigger several commands ==== | ==== To trigger several commands ==== | ||
| <code> | <code> | ||
| Línea 71: | Línea 66: | ||
| </code> | </code> | ||
| - | ==== Messages ==== | ||
| + | ==== Trigger after one calling ==== | ||
| + | |||
| + | You can do something like this for sending message ''UpdateTotals'' with value 100: | ||
| + | <code> | ||
| + | GetAccount result -> case result of | ||
| + | Ok account -> ({model | account = account }, Task.succeed (UpdateTotals 100.0) |> Task.perform identity) | ||
| + | Err err -> log (toString err) (model, Cmd.none) | ||
| + | </code> | ||
| + | |||
| + | Or just define: | ||
| + | <code> | ||
| + | send : msg -> Cmd msg | ||
| + | send msg = Task.succeed msg |> Task.perform identity | ||
| + | </code> | ||
| + | |||
| + | ==== Notes ==== | ||
| + | * If something waits for a Command but you do not have any Command to apply you can send ''Cmd.none''. | ||
| ===== Subscriptions ===== | ===== Subscriptions ===== | ||
| Línea 140: | Línea 151: | ||
| ==== Flags. Js values on app initialization ==== | ==== Flags. Js values on app initialization ==== | ||
| - | Flags are a way to pass values into Elm on initialization. | + | Flags are a way to pass values into Elm on initialization. The idea is that you use the type of those values that are passed to your script for produce the first model status. |
| + | |||
| + | So an initial function like this: | ||
| + | <code> | ||
| + | init : () -> (Model, Cmd Msg) | ||
| + | init _ = | ||
| + | ( initialModel, Http.get{ url = "/api/bookmarks", expect = Http.expectJson BookmarksReceived resultsDecoder} ) | ||
| + | </code> | ||
| + | |||
| + | With Flags will be similar to this: | ||
| + | <code> | ||
| + | init : FlagsType -> (Model, Cmd Msg) | ||
| + | </code> | ||
| In JS we can create the application with the chosen flags: | In JS we can create the application with the chosen flags: | ||
| Línea 200: | Línea 223: | ||
| * Ports are available for applications, not for packages. | * Ports are available for applications, not for packages. | ||
| - | === JS -> Elm === | + | === Ports: JS -> Elm === |
| In javascript: | In javascript: | ||
| <code javascript> | <code javascript> | ||
| Línea 228: | Línea 251: | ||
| - | === Elm -> JS === | + | === Ports: Elm -> JS === |
| In Elm: | In Elm: | ||
| Línea 319: | Línea 342: | ||
| ===== Encoders and Decoders ===== | ===== Encoders and Decoders ===== | ||
| - | :!: | + | ==== Useful ==== |
| + | === succeed === | ||
| + | |||
| + | You can set a fixed value with ''Decode.succeed'': | ||
| + | <code> | ||
| + | decodePageGroupForm : T.PageGroup -> D.Decoder T.PageGroup | ||
| + | decodePageGroupForm group = D.map5 T.PageGroup | ||
| + | (D.succeed group.uuid) | ||
| + | (D.at ["target", "title", "value"] D.string) | ||
| + | (D.succeed group.subtitle) | ||
| + | (D.succeed group.order) | ||
| + | (D.succeed group.pages) | ||
| + | | ||
| + | |||
| + | zineDecoder : D.Decoder T.Zine | ||
| + | zineDecoder = D.map4 T.Zine | ||
| + | (D.field "uuid" D.string) | ||
| + | (D.field "title" D.string) | ||
| + | (D.field "cover" D.string) | ||
| + | {- (D.maybe (D.field "groups" <| D.list groupDecoder)) -} | ||
| + | (D.maybe (D.succeed [])) | ||
| + | </code> | ||
| + | |||
| + | === oneOf === | ||
| + | |||
| + | It tries a decoder, if fails, tries the next one and so on: | ||
| + | <code> | ||
| + | groupDecoder : D.Decoder T.PageGroup | ||
| + | groupDecoder = D.map5 T.PageGroup | ||
| + | (D.field "uuid" D.string) | ||
| + | (D.field "title" D.string) | ||
| + | (D.oneOf [D.field "subtitle" D.string, D.succeed ""]) -- If subtitle is null, a different type than string... it will put "" | ||
| + | (D.field "order" D.int) | ||
| + | (D.field "pages" <| D.list pageDecoder) | ||
| + | </code> | ||
| + | |||
| + | ==== Maps ==== | ||
| + | |||
| + | Lets imagine we want to produce a ''Message'' when the Decoder has decoded the the object. | ||
| + | |||
| + | |||
| + | This can be chained. Lets imagine the [[https://package.elm-lang.org/packages/elm/html/latest/Html-Events#preventDefaultOn|preventDefaultOn]] of a form: | ||
| + | <code> | ||
| + | type Message = FormSubmission FormFields | ||
| + | |||
| + | type alias FormFields = { ... } | ||
| + | |||
| + | update : Message -> Model -> Model | ||
| + | update msg model = case msg of | ||
| + | FormSubmission _ -> { model | counter = model.counter + 1 } | ||
| + | |||
| + | decodeForm = Decode.map2 FormFields ... | ||
| + | |||
| + | view : Model -> Html.Html Message | ||
| + | view model = | ||
| + | let | ||
| + | alwaysPreventDefault : msg -> ( msg, Bool ) | ||
| + | alwaysPreventDefault msg = ( msg, True ) | ||
| + | in | ||
| + | Html.div [] [ | ||
| + | Html.form [Events.preventDefaultOn "submit" (Decode.map alwaysPreventDefault (Decode.map FormSubmission decodeForm))] [ | ||
| + | ... | ||
| + | </code> | ||
| ===== Useful types ===== | ===== Useful types ===== | ||
| Línea 370: | Línea 455: | ||
| ==== Create a program without a view ==== | ==== Create a program without a view ==== | ||
| Use ''Platform.worker''. Documentation [[https://package.elm-lang.org/packages/elm/core/1.0.5/Platform#worker|here]]. | Use ''Platform.worker''. Documentation [[https://package.elm-lang.org/packages/elm/core/1.0.5/Platform#worker|here]]. | ||
| - | ===== Gotchas ===== | ||
| - | Every function that accepts two arguments can be converted in one that accepts one argument: | ||
| - | <code> | ||
| - | > String.repeat | ||
| - | <function> : Int -> String -> String | ||
| - | |||
| - | > String.repeat 4 | ||
| - | <function> : String -> String | ||
| - | </code> | ||