dtwrks / elm-book / ElmBook.Actions

This module focuses on actions – a.k.a messages your book may send to its runtime. There are mainly two types of actions:

Logging Actions

Take a look at the "Logging Actions" guide for some examples.

Tip If you want to test anchor elements without actually changing the current url, just pass in an url like /logAction/some-url. Your book will intercept any url change starting with /logAction and will log the action intent.

logAction : String -> ElmBook.Internal.Msg.Msg state

Logs an action that takes no inputs.

-- Will log "Clicked!" after pressing the button
button [ onClick <| logAction "Clicked!" ] []

logActionWithString : String -> String -> ElmBook.Internal.Msg.Msg state

Logs an action that takes one String input.

-- Will log "Input: x" after pressing the "x" key
input [ onInput <| logActionWithString "Input" ] []

logActionWithBool : String -> Basics.Bool -> ElmBook.Internal.Msg.Msg state

Logs an action that takes one Bool input.

logActionWithInt : String -> String -> ElmBook.Internal.Msg.Msg state

Logs an action that takes one Int input.

WARNING:

Folks, this is function is currently broken, my bad. It will be fixed in the next major release (which won't take long). Until then please use the following replacement:

logActionWith String.fromInt

logActionWithFloat : String -> String -> ElmBook.Internal.Msg.Msg state

Logs an action that takes one Float input.

WARNING:

Folks, this is function is currently broken, my bad. It will be fixed in the next major release (which won't take long). Until then please use the following replacement:

logActionWith String.fromFloat

logActionWith : (value -> String) -> String -> value -> ElmBook.Internal.Msg.Msg state

Logs an action that takes one generic input that can be transformed into a String.

eventToString : Event -> String
eventToString event =
    case event of
        Start ->
            "Start"

        Finish ->
            "Finish"

myCustomComponent {
    onEvent =
        logActionWith
            eventToString
            "Received event"
}

Update Actions

Tip: I highly recommend you read the "Stateful Chapters" guide to learn more about update actions and stateful chapters.

updateState : (state -> state) -> ElmBook.Internal.Msg.Msg state

Updates the state of your stateful book.

counterChapter : Chapter { x | counter : Int }
counterChapter =
    let
        update state =
            { state | counter = state.counter + 1 }
    in
    chapter "Counter"
        |> withStatefulComponent
            (\state ->
                button
                    [ onClick (updateState update) ]
                    [ text <| String.fromInt state.counter ]
            )

updateStateWith : (a -> state -> state) -> a -> ElmBook.Internal.Msg.Msg state

Used when updating the state based on an argument.

inputChapter : Chapter { x | input : String }
inputChapter =
    let
        updateInput value state =
            { state | input = value }
    in
    chapter "Input"
        |> withStatefulComponent
            (\state ->
                input
                    [ value state.input
                    , onInput (updateStateWith updateInput)
                    ]
                    []
            )

updateStateWithCmd : (state -> ( state, Platform.Cmd.Cmd (ElmBook.Internal.Msg.Msg state) )) -> ElmBook.Internal.Msg.Msg state

Updates the state of your stateful book and possibly sends out a command. HTTP requests inside your book? Oh yeah! Get ready to go full over-engineering master.

counterChapter : Chapter { x | counter : Int }
counterChapter =
    let
        fetchCurrentCounter state =
            ( state
            , fetchCounterFromServer <|
                updateState updateCounter
            )

        updateCounter newCounter state =
            { state | counter = newCounter }
    in
    chapter "Counter"
        |> withStatefulComponent
            (\state ->
                button
                    [ onClick (updateStateWithCmd fetchCurrentCounter) ]
                    [ text <| String.fromInt state.counter ]
            )

updateStateWithCmdWith : (a -> state -> ( state, Platform.Cmd.Cmd (ElmBook.Internal.Msg.Msg state) )) -> a -> ElmBook.Internal.Msg.Msg state

Same as updateStateWith but should return a ( state, Cmd msg ) tuple.

"The Elm Architecture" helpers

If you're working on a module with its own elm architecture, these might make things a little simpler. Everything here could be done with updateState but why not make things easier for ourselves?

-- Your UI module stuff

type alias Model = ...
type Msg = ...

update : Msg -> Model -> Model
view : Model -> Html msg

-- The elm-book stuff

type alias ElmBookModel a =
    { a | inputModel : Model }

chapter : Chapter (ElmBookModel a)
chapter "Chapter with elm architecture"
    |> renderStatefulComponent (\{ inputModel } ->
        view inputModel
            |> Html.map (
                mapUpdate
                    { toState = \state model -> { state | inputModel = model }
                    , fromState = \state -> state.inputModel
                    , update = update
                    }
                )
    )

mapUpdate : { fromState : state -> model, toState : state -> model -> state, update : msg -> model -> model } -> msg -> ElmBook.Internal.Msg.Msg state

Maps a custom msg to an elm-book msg.

mapUpdateWithCmd : { fromState : state -> model, toState : state -> model -> state, update : msg -> model -> ( model, Platform.Cmd.Cmd msg ) } -> msg -> ElmBook.Internal.Msg.Msg state

Same as mapUpdate but used when your update returns a ( model, Cmd msg ) tuple.