How to use Nav.pushUrl in sub page while using hot-reload?

According to Structure · An Introduction to Elm , I made my sub page looks like this pseudo code:

(The point is that in order to use Nav.pushUrl in sub page, I saved Nav.Key in both main Model and Session . If I remove Nav.Key from Model, elm-hot will report key location changed.)

Main.elm

type alias Model =
    { key: Nav.Key
    , page: Monitor Monitor.Model
}

type Msg =
    MonitorMsg Monitor.Msg

-- Cmd.map Monitor msg

Monitor.elm

type alias Model =
    { session: { key: Nav.Key } }

type Msg =
    DeviceIdChanged Int

Say, if DeviceIdChanged 1 , I need to use Nav.pushUrl key to load my url to /monitor/1

I currently pass key to session during Monitor.init , but:

  • If I add a blank line to my source code, which triggers an elm-hot reload, then cast the DeviceIdChanged 1 to cast a Nav.pushUrl to re-step into my page.

The init cmds in my page will not be casted, and open the debugger will spam these errors in console:

Uncaught TypeError: Cannot read properties of undefined (reading 'childNodes')
    at _VirtualDom_addDomNodesHelp (eval at hmrApply (runtime-900e2ded8fe2c4a1.js:322:16), <anonymous>:2448:34)
  • If I avoid the elm-hot reload (by not modifying my source code), the Nav.pushUrl works fine.

  • If I use a a [href "monitor/1"] [] to trigger onUrlRequest = LinkClicked , it also works fine even if I modified source code and after triggered elm-hot reload.

So I guess maybe something broken while I use Nav.pushUrl key which takes key from Monitor.Model session, which different from main Model key.

Is there another elegant way to share global Model state or cast global Msg in sub page? (Different with session which potentially change Nav.Key location)

Or if dumping all pages into Main.elm is a better solution, why the structure guide is teaching us this technology, both in package.elm-lang.org and elm-spa-example ?

– UPDATE

I can confirm that introducing a GlobalMsg thus let Main.elm handle Nav.pushUrl using Model key can solve this problem.

I end up using this OutMsg pattern:

Main.elm

type Msg =
    GlobalMsg Global.Msg
    -- ...

And add some return helpers to simplify tuple building:

Global.elm

type Msg =
    -- ...

return : model -> ( model, Cmd msg, Cmd Msg )
return model =
    ( model, Cmd.none, Cmd.none )


return2 : model -> Cmd msg -> ( model, Cmd msg, Cmd Msg )
return2 model cmd =
    ( model, cmd, Cmd.none )
1 Like

You could share Nav.Key in a Session module and use it in your main module and sub-pages. It’s better to have a single source of truth.

For elm-hot , the technical issue is that this method will lead to key location changed , thus it will disable hot reloading when url changed.

1 Like

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