FabienHenon / app-object / AppObject

The AppObject is an object that encapsulates the Model and Cmd Msg of a component (returned in side effect functions like init or update) plus and appData object and a Cmd appMsg. These new elements are a model and commands related to the entire application.

Let's say for instance that you have a component that does something (whatever) and that needs to open a modal, or set the connected user, or set the user language of the application, ... All of these states/effects are related to the application, not to the component. Indeed, the component itself can't open a modal because it's the application's responsibility. Also, the component could save the connected user to its own state, but it's a data the entire application would like to know about and with the classic architecture of elm apps it's not possible for a component to tell the app that it should update its state.

To make it simpler: a component can't change the state of its parent component and can't send commands with its parent's messages.

This is what AppObject is for, it allows you to:

Definitions


type AppObject appData appMsg model msg

AppObject is the object you should return from your side effect functions (init, update) in your components.

I suggest your create a module that defines your appData model and your appMsg message type, and you define a type alias of your own AppObject with the appData and appMsg set :

type alias MyAppObject model msg =
    AppObject.AppObject Data AppMsg model msg

type alias Data =
    { isModalOpen : Bool
    }

type AppMsg
    = ToggleModal Bool

Init

init : appData -> model -> AppObject appData appMsg model msg

Creates a new AppObject from the appData and your component's model

batchCmd : Platform.Cmd.Cmd msg -> AppObject appData appMsg model msg -> AppObject appData appMsg model msg

Adds a new component's command to this AppObject

batchAppCmd : Platform.Cmd.Cmd appMsg -> AppObject appData appMsg model msg -> AppObject appData appMsg model msg

Adds a new global command to this AppObject

batchCmdWithModel : (model -> ( model, Platform.Cmd.Cmd msg )) -> AppObject appData appMsg model msg -> AppObject appData appMsg model msg

Adds a new component's command to this AppObject? The model is passed as parameter

batchAppCmdWithModel : (model -> ( model, Platform.Cmd.Cmd appMsg )) -> AppObject appData appMsg model msg -> AppObject appData appMsg model msg

Adds a new global command to this AppObject. The model is passed as parameter

Mappers

map : (modelA -> modelB) -> (appDataA -> appDataB) -> (msgA -> msgB) -> (appMsgA -> appMsgB) -> AppObject appDataA appMsgA modelA msgA -> AppObject appDataB appMsgB modelB msgB

Maps your AppObject to change the types of appData, appMsg, model and msg

mapAppData : (a -> appData) -> AppObject a appMsg model msg -> AppObject appData appMsg model msg

Maps only your appData

mapAppMsg : (a -> appMsg) -> AppObject appData a model msg -> AppObject appData appMsg model msg

Maps only your appMsg

mapModel : (a -> model) -> AppObject appData appMsg a msg -> AppObject appData appMsg model msg

Maps only your model

mapMsg : (a -> msg) -> AppObject appData appMsg model a -> AppObject appData appMsg model msg

Maps only your msg

Advanced usage

merge : (modelB -> modelA -> modelC) -> (appDataB -> appDataA -> appDataC) -> (msgA -> msgC) -> (msgB -> msgC) -> (appMsgA -> appMsgC) -> (appMsgB -> appMsgC) -> AppObject appDataA appMsgA modelA msgA -> AppObject appDataB appMsgB modelB msgB -> AppObject appDataC appMsgC modelC msgC

Merges 2 AppObjects together. You provide the functions used to:

foldl : (a -> AppObject appData appMsg model msg -> AppObject appData appMsg model msg) -> List a -> AppObject appData appMsg model msg -> AppObject appData appMsg model msg

Reducer that allows you to update or create an AppObject for each element of a list

andThen : (appDataA -> modelA -> AppObject appDataB appMsg modelB msg) -> AppObject appDataA appMsg modelA msg -> AppObject appDataB appMsg modelB msg

Allows you to create a new AppObject from an existing one, using the appData and the model. The new Cmd appMsg and Cmd msg will be batched to the existing ones

Usage

run : (appData -> model -> model) -> (appMsg -> msg) -> AppObject appData appMsg model msg -> ( model, Platform.Cmd.Cmd msg )

Executes your AppObject. That means that you will create a ( model, Cmd msg ) tuple from an AppObject, this allows you to run your side effects and model updates in your root update and init functions