Empty links, i.e. a
elements without a href
attribute or with href ""
causes a page reload if used with Browser.application
in Elm 0.19.
Here's a minimal, complete and verifiable example:
module Main exposing (main)
import Browser
import Browser.Navigation
import Html exposing (..)
import Url
type alias Model =
()
type Msg
= UrlRequested Browser.UrlRequest
| UrlChanged Url.Url
init () _ _ =
( (), Cmd.none )
update msg model =
case msg of
UrlRequested (Browser.Internal _) ->
( model, Cmd.none )
UrlRequested (Browser.External url) ->
( model, Browser.Navigation.load url )
UrlChanged _ ->
( model, Cmd.none )
view model =
{ title = ""
, body = [ a [] [ text "click to reload" ] ]
}
main =
Browser.application
{ init = init
, view = view
, update = update
, subscriptions = \_ -> Sub.none
, onUrlRequest = UrlRequested
, onUrlChange = UrlChanged
}
This is non-standard behavior, as such links should not be considered hyperlinks by the user agent, and a lot of code depend on this behavior, among them elm-bulma
.
This is caused by Elm attaching onclick
event listeners to all a
elements to be able to intercept and handle routing internally. It parses the URL and categorizes it as either Internal
or External
, where an empty or omitted href
is apparently considered External
. Elm will then create a 'Msg' using the type constructor passed to Browser.application
via onUrlRequest
, run update
passing this Msg
, and this is where we can intercept and handle it appropriately.
The solution is to add another pattern to update
which matches on empty external URL, where we simply do nothing instead of trying to load
the URL as we normally would with other external URLs. In regards to the question's example the following updated update
function should do the trick:
update msg model =
case msg of
UrlRequested (Browser.Internal _) ->
( model, Cmd.none )
UrlRequested (Browser.External "") ->
( model, Cmd.none )
UrlRequested (Browser.External url) ->
( model, Browser.Navigation.load url )
UrlChanged _ ->
( model, Cmd.none )