I have a modal window that can display different components inside it. Each component has it's own updater and messages, but I want to share a close button between them.
Thus I can't call "CloseModal" directly from my children — Elm doesn't allow me to call someone else messages. What are my options?
I thought I could call "Modal.Update.update Modal.Messages.CloseModal", but inside my components I have only chunks of a state. So it's not a option.
Then I found a way to pass messages from parent to child, but it doesn't help me to pass messages other way around. Or to siblings.
In short, you can not pass messages directly from child to parent or a sibling.
Elm Architecture implements uni-directional message passing, in other words, your parent component is always aware of messages for child components before child component will receive a message.
I have made a simple example of parent-child communication, it is way too big to embed it into an answer so that I will note only the key points here.
Child component defines a set of Messages:
type Msg
= Update Model
| Focus
| Blur
In it's update
function we ignore Messages, intended for the parent component.
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Update value ->
( value, Cmd.none )
-- Ignore the rest of the messages.
_ ->
( model, Cmd.none )
In parent's update
function we can pattern match required messages and react to them.
The rest of the messages will go through default branch.
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NameMsg childMsg ->
case childMsg of
{- We have intercepted a message from child component.
This part of the update function might be moved
to a separate function for better readability.
-}
Input.Focus ->
update (HelperMsg Helper.Show) model
Input.Blur ->
update (HelperMsg Helper.Hide) model
-- The default message passing routine.
_ ->
let
( nameModel, nameCmd ) =
Input.update childMsg model.name
in
( { model | name = nameModel }
, Cmd.map NameMsg nameCmd
)
The example above concludes the child-parent and sibling communication. You can run the update function recursively as much as you want with any messages to any components.
update
functionCmd.Extra exposes a function for sending messages.
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model ->
(model, message SomeMessage)
PS: Translator pattern example is on my To-do, leave a comment if you want me to update the answer with it.