Child to parent message passing with label for hack

I was looking for the most concise way to close a simple modal (this problem again…) and I tried jamming a hidden button on my parent like

button [ id "Parent.CloseDialogMessage", onClick CloseDialogMessage ]

and then putting a separate button inside my child/modal with a

label [ for "Parent.CloseDialogMessage" ]

Obviously seems like it’s a mega-hack… but it works! And while the compiler won’t catch this if I forget to render the parent button with the child dialog, if I’m real careful ™ about always rendering the two together, it seems like the message shouldn’t get lost.

This saves me enough boilerplate not using OutMsg or translating from child to parent that it would be worth it if maintaining this were the only sacrifice.

Has anyone tried this already? Is there a good reason other than the obvious flaw listed that I shouldn’t go forward with this approach?

Would love to hear your thoughts. Thanks!

The most concise way would be to just use a function that renders the modal and provide CloseDialogMessage as a argument to that function:

fooModal : msg -> Html msg 
fooModal closeDialog =
    div [class "modal"] [p [] [text "Foo"], button [onClick closeDialog] [text "Ok"]]

You are creating a tight coupling between parent and child. Basically, you are relying on implementation details instead of relying on an interface.

In my basic understanding, a child module with its own Msg type can’t render a view that emits different messages, correct? So to maintain its own model/update/etc (which I believe is a common paradigm), I’d have to use one of the aforementioned techniques.

To import the messages of the child in my parent module and check for the child’s messages would also create a tight coupling wouldn’t it? Every other option as I understood it would require the same level of knowledge between either module.

something as simple as a simple modal should not need the full triad. The problems people get into with boilerplate are sometimes created by the fact that they reach for the triad way too soon.

Not really. The child OutMsg behaves as an interface. It is a contract that one can keep stable.

For simple state, I sometime use the (State, OutMsg) pattern that you can see in this example:
https://ellie-app.com/5L5RHZ2Jmw6a1

I agree with @pdamoc, just provide CloseDialogMessage as a argument.

We’ve created a modal component a time ago where we used a similar function how suggest pdamoc. You can find an inspiration here or in demo. Component enables to pass a parent msg to modal window and also you can change a css style of this component (see example). But, it’s still waiting on CR and writing documentations before we’ll put in to elm-package.

Thank you both for the suggestions and examples! I feel I can take some inspiration from both. I fear I also may have oversimplified my original question and missed the core of my problem.

I have ~20 unique forms I must present, each with multiple steps and varying data for users to input text and upload various files. A user can select from a list and the form appears in a modal. In order to manage the scale of a keeping different presentation flows and network requests etc. I kept the forms in separate modules. I couldn’t originally imagine a way to re-use most of the code between them.

That may be too “off-topic” for this so I don’t expect much more, but if you care to chime in with any advice or examples on an approach, I’d appreciate it. Thanks again and cheers

You could use something like this:

fooModal : msg -> Html msg -> Html msg  
fooModal closeDialog content = 
    div [class "modal"] [content, button [onClick closeDialog] [text "Close"]]

If you want more functionality move to a record configuration.

type alias ModalConfig msg =
    { save : msg
    , cancel : msg
    , content : Html msg
    }


modal : ModalConfig msg -> Html msg
modal { save, cancel, content } =
    div [ class "modal" ]
        [ content
        , div [ class "buttons" ]
            [ button [ onClick save ] [ text "Save" ]
            , button [ onClick cancel ] [ text "Cancel" ]
            ]
        ]

your form view would end up being the content of this modal.

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