Catching sub module Msg

Hello,

I currently have a project (0.19) where I’m trying to implement ‘components’ in sub modules and each have their own Model, Msg, view, update, subscriptions which are mapped in Main.

It seems to work fine, apart from one issue I can’t get my head around, I want to catch messages of a certain type from one of these sub modules.

In this example, I have a SearchBar module (component) which subscribes to “Enter” key presses generating a Search Msg for the update function.

From Main I can send a Search Msg from an exposed type constructor in the SearchBar module (such as when a button is pressed), but Main also needs to know when a Search Msg is triggered from the Enter key.

In my Main update function these messages are being mapped, so it seems as though I should be able to write a case for the messages I’m interested in, but for the life of me I can’t get it! Any suggestions?

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    let

        fromSearchBar =
            \( mdl, cmd ) -> ( { model | searchBar = mdl }, Cmd.map GotSearchBarMsg cmd )
    in
    case msg of
        GotSearchBarMsg message ->
            SearchBar.update message model.searchBar
                |> fromSearchBar

EDIT

I solved this problem by subscribing to the key board events directly in Main. This meant I also had to expose more of the sub modules Msg constructors.

If you are doing this style of nested TEA, its usually a bad sign if your child modules Msg is fully exposed - Msg is for the internal commands that the module may create, and I always make them opaque.

One way is to use a so called out message, and note that the Out type is fully exposed. In the child module:

module SearchBar exposing (Model, Msg, Out(..), update, view)

type alias Model = 
    { searchString : String
    , ...
    }

type Out = 
    SearchFor String

type Msg 
    = PressedEnter
    | ...


update : Model -> Msg -> (Model, Cmd Msg, Maybe Out)
update model msg = 
    case msg of 
        PressedEnter -> (model, Cmd.none, SearchFor model.searchString |> Just)

The thing to get your head around is that update functions are not special - they are just functions, and you can have them any way you like.

An alternative that might work better, is to not split your search bar out into a child module. You only need 1 of them, and it is clearly quite closely integrated with the rest of the application, so you might just be making things harder for youself by doing it that way. Definitely watch this, if you have not already: https://www.youtube.com/watch?v=DoA4Txr4GUs

Thanks Rupert!

You are an absolute champion! That’s such a good observation, I was on board with the idea that the sub modules update is just a function, but hadn’t fully grasped that I could (or should) add extra data to the returned type.

I’m going to take a look at the linked video, however I think (hope) in this instance it is justified :grimacing:

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