villasv
villasv

Reputation: 6861

Handling messages when composing with list of widgets in Elm

In a few guides, message handling in parent components is made like this;

type Msg
    = NavMsg Nav.Msg
    | SidebarMsg Sidebar.Msg
    | WidgetMsg Widget.Msg

And parent components handle them in updates with:

update : Msg -> AppModel -> (AppModel, Cmd Msg)
update message model =
    case message of
        WidgetMsg subMsg ->
            let
                (updatedWidgetModel, widgetCmd) =
                    Widget.update subMsg model.widgetModel
            in
                ({ model | widgetModel = updatedWidgetModel }, Cmd.map WidgetMsg widgetCmd)
        _ ->

However, I couldn't find a simple way to do the same if the child components are inside a list. How can I tell the correct sub component to react to a message directed to him?

I thought of adding the component object to the message:

type Msg
    = MessageToParent
    | MessageToChild Child Child.Msg

But this seems very inefficient if the Child component is big, and still gives me trouble when trying to delegate the inner Child.Msg to the right Child.

What's the best way to handle message passing to a list of components?

Upvotes: 0

Views: 219

Answers (1)

Simon H
Simon H

Reputation: 21047

I would suggest using an array (or Dict) and code like this

type Msg
    = WidgetMsg Int Widget.Msg

update : Msg -> AppModel -> (AppModel, Cmd Msg)
update message model =
    case message of
        WidgetMsg idx subMsg ->
            model.widgetModels
                |> Array.get idx
                |> Maybe.map (Widget.update subMsg)
                |> Maybe.map (\(m,c) -> 
                     ({ model | widgetModels = Array.set idx m model.widgetModels }
                     , Cmd.map Widgetmsg idx c)
                     )
                |> Maybe.withDefault (model, Cmd.none)
        _ ->

Upvotes: 2

Related Questions