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
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.