Search code examples
elm

Failure trying to switch between two embedded Elm apps in the same node


I am trying to dynamically switch between Elm apps based on user input.

Both apps are transpiled in js files via elm make (Eg : Foo.js exposing module Foo and Bar.js exposing module Bar)

Two buttons run the usual "Elm.[Foo|Bar].init(node:document.querySelector('main')" so that in theory I could switch between rendering either of the apps.

<html>
<head>
  <script src="[..]/foo.js"></script>
  <script src="[..]/bar.js"></script>
</head>
<body>
  <main></main>

  <input value="Foo" type="button" name="Foo" onclick="Elm.Foo.init({node:document.querySelector('main')});">
  <input value="Bar" type="button" name="Bar" onclick="Elm.Bar.init({node:document.querySelector('main')});">
</body>
</html>

To be clear, both apps should alternate in taking over the element.

When I hit either of the buttons for the first time, the app renders correctly, but a second click produces the following error

Error: What node should I take over? In JavaScript I need something like:

    Elm.Main.init({
        node: document.getElementById("elm-node")
    })

You need to do this with any Browser.sandbox or Browser.element program.

And indeed the element is somehow deleted upon rendering the first app.

I could not find any mention of this behaviour in the docs and I would like to know if it is possible to prevent this from happening in any way, and if it is expected behaviour.

Thanks in advance


Solution

  • The reason is that the first Elm module will replace the <main> tag with the elm view so the next Elm module cannot find that <main> tag anymore. You can check on the dev tool.

    My solution: Wrap your views with the main tag like this.

    Foo.elm

    view model =
      node "main" 
        []
        [ div [] [ text "foo foo foo" ] ]
    

    Bar.elm

    view model =
      node "main" 
        []
        [ div [] [ text "bar bar bar" ] ]
    

    So It can find and replace the <main> tag for the second button.