How to map general messages from DB to component modules

I have a generic message for GotDbData DbDocInfo for any data message sent to Elm from the DB subscription/port, data is fetched in js from Firestore client. But I am trying to break up my SPA into component/page modules that handle their own messaging.

What is a good way to map generic GotDbData Msg into a module specific message like Levels.Msg? Or am I thinking about this in the wrong way? Would I need a separate subscription to channel the data to each module?

Main.elm
type Msg
= ChangedUrl Url
| GotLoginMsg Login.Msg
| GotLevelsMsg Levels.Msg
| GotDbData DbDocInfo
..
subscriptions _ =
Ports.dataFromDb GotDbData
..
update msg model =
case ( msg, model.pageView ) of
-- Delegate to module
( GotLevelsMsg levelsMsg, Levels levelsModel ) ->
let
( newLevelsModel, newLevelsMsg ) =
Levels.update levelsMsg levelsModel
in
( { model | pageView = Levels newLevelsModel }, Cmd.none )
-- From DB
-- map generic messages from DB to a new msg based on current pageView
( GotDbData data, Levels levelsModel ) ->
-- how to handle this?

Indentations don’t seem to be showing up consistently, hopefully it is still decipherable.

You could pass the data to your update function for the current page and handle the data internally in the page module. The only update function that needs to follow Msg -> Model -> (Model, Cmd Msg) is your top level update function in Main.elm. Your individual pages can receive and return whatever makes sense for them.

Alternatively, you could handle it in your subscriptions function. Something like this:

subscriptions : Model -> Sub Msg
subscriptions { pageView } =
    case pageView of
        Levels _ ->
            Levels.subscriptions
                 |> Sub.map GotLevelsMsg

Then each of your pages can implement their own subscriptions function where necessary.

You could also do something like this:

subscriptions : Model -> Sub Msg
subscriptions { pageView } =
    case pageView of
        Levels _ ->
            Levels.subscriptions GotLevelsMsg

And then Levels.subscriptions would return GotLevelsMsg Msg, so your type annotation would be something like this:

subscriptions : (Msg -> msg) -> Sub msg

I’ve used both approaches, but tend to favour the second.

HTH

p.s. if you wrap your code in ``` (three backticks) you’ll be able to indent your code snippets :slight_smile:

1 Like

Thank you so much for this detailed info and recommendation!

I was stumbling my way toward the second approach, but this extra context really helps clarify things a lot more and expand my awareness. Very much appreciated!

1 Like

NP, glad it helped :slight_smile:

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.