Orasund / elm-action / Action

There is a quick guideline to follow if you want to use this module:

  1. Add a type alias. For example:

     type alias UserAction =
         Action
             Never --Allow Updates?
             Never --Allow Cmd other then Cmd.none?
             Never --Allow Transitions?
             Never --Allow Exit?
    
  2. Start by setting the first Never to your stateModel:

     type alias UserAction =
         Action
             UserModel -- updates allowed.
             Never --Allow Cmd other then Cmd.none?
             Never --Allow Transitions?
             Never --Allow Exit?
    

    If you want to allow Cmd, change the second Never to your stateMsg. In our example, this would be UserMsg.

  3. Write your update function. In our very basic example, it looks like this:

     update : Msg -> Model -> (Model, Cmd Msg)
     update msg model =
         case msg of
             (UserSpecific userMsg,User userModel) ->
                 updateUser userMsg userModel
                 |> Action.config
                 |> Action.withUpdate User never
                 -- If you want to allow Cmd you would use
                 -- the following line
                 --|> Action.withUpdate User UserSpecific
                 |> Action.apply
    
             _ ->
                 (model,Cmd.none)
    
  4. If needed, go back to Step 2 and replace another Never.

Actions


type Action model msg transitionData exitAllowed

An Action specifies the behaviour of an update function. An Action can either be

An Action has 4 type parameters: model,msg,transitionData and exitAllowed.

updating : ( stateModel, Platform.Cmd.Cmd stateMsg ) -> Action stateModel stateMsg transitionData exitAllowed

Updates the model as usual.

import Task

updating (42, Cmd.none)
|> Action.config
|> Action.withUpdate (\int -> (int,0)) never
|> Action.apply
|> Tuple.first
--> (42,0)

Checklist in case of errors:

transitioning : transitionData -> Action stateModel stateMsg transitionData exitAllowed

Transitions to a different model.

import Task

transitioning 42
|> Action.config
|> Action.withTransition (\int -> ((int,0),Cmd.none)) Just never
|> Action.apply
|> Tuple.first
--> Just (42,0)

Checklist in case of errors:

exiting : Action stateModel stateMsg transitionData ()

Transitions to a different model with less access. (like logging out)

import Task

exiting
|> Action.config
|> Action.withExit ((42,0),Cmd.none)
|> Action.apply
|> Tuple.first
--> (42,0)

Checklist in case of errors:

Config Pipeline

config : Action stateModel stateMsg transitionData exitAllowed -> ActionConfig stateModel stateMsg transitionData exitAllowed (Config (Basics.Never -> ( model, Platform.Cmd.Cmd msg )) (Basics.Never -> model) (Basics.Never -> msg) (Basics.Never -> ( model, Platform.Cmd.Cmd msg )))

Starts the configuration of the Action.

The most basic config pipeline looks like this:

updateFunction
    |> Action.config
    |> Action.apply

with updateFunction : Model -> Msg -> Action Model Msg TransitionData ExitAllowed.

You will need to add withExit,withUpdate and or withTransition to make the code compile.

apply : ActionConfig stateModel stateMsg transitionData exitAllowed { exitFun : exitAllowed -> ( model, Platform.Cmd.Cmd msg ), modelMapper : stateModel -> model, msgMapper : stateMsg -> msg, transitionFun : transitionData -> ( model, Platform.Cmd.Cmd msg ) } -> ( model, Platform.Cmd.Cmd msg )

Ends the Configuration and returns a (Model, Cmd Msg).

withUpdate : (stateModel -> model) -> (stateMsg -> msg) -> ActionConfig stateModel2 stateMsg transitionData exitAllowed (Config a b c d) -> ActionConfig stateModel2 stateMsg transitionData exitAllowed (Config a (stateModel -> model) (stateMsg -> msg) d)

Specifies how the stateModel/stateMsg is embedded in the main model/msg.

Lets say we have a password protected area:

type Model
    = Maybe RestrictedModel

type Msg
    = GuestSpecific GuestMsg
    | RestrictedSpecific RestrictedMsg

Then we would use withUpdate Just RestrictedSpecific for the restricted area and withUpdate (always Nothing) GuestSpecific for the guest area.

Checklist in case of errors:

withTransition : (transitionData -> ( stateModel2, Platform.Cmd.Cmd stateMsg2 )) -> (stateModel2 -> model) -> (stateMsg2 -> msg) -> ActionConfig stateModel stateMsg transitionData2 exitAllowed (Config a b c d) -> ActionConfig stateModel stateMsg transitionData2 exitAllowed (Config a b c (transitionData -> ( model, Platform.Cmd.Cmd msg )))

Specifies how the state transitions to another state.

Lets say we want a user to login.

type alias User =
    { name : String
    , admin : Bool
    }

initUser : String -> User
initUser string =
    { name = string
    , admin = string == "Admin"
    }

type Model
    = Maybe User

Then we can use withTransition \string -> ( initUser string, Cmd.none) Just never for logging in a user.

Checklist in case of errors:

withCustomTransition : (transitionData -> ( model, Platform.Cmd.Cmd msg )) -> ActionConfig stateModel stateMsg transitionData2 exitAllowed (Config a b c d) -> ActionConfig stateModel stateMsg transitionData2 exitAllowed (Config a b c (transitionData -> ( model, Platform.Cmd.Cmd msg )))

Specifies a Transition to multiple possible states.

Checklist in case of errors:

withExit : ( model, Platform.Cmd.Cmd msg ) -> ActionConfig stateModel stateMsg transitionData () (Config (Basics.Never -> ( model, Platform.Cmd.Cmd msg )) b c d) -> ActionConfig stateModel stateMsg transitionData () (Config (() -> ( model, Platform.Cmd.Cmd msg )) b c d)

Specifies the state the resulting (model, Cmd msg) when exiting.

For a hard exit you can use

withExit (init ())

Checklist in case of errors: