14

Is there a way to simply go to a new webpage in Elm, similar to clicking on a link?

I have a button that when clicked I want to take the user to another webpage. I know I could make that an a element and use CSS to style it like a button. However, I'm using elm-mdl to create material design lite buttons and I'd like to know how to do this regardless.

I've tried creating a GoTo String Msg and firing that on the button click with Button.onClick (GoTo "newpage.html"), but I don't know what to put for the Cmd. I tried the following:

GoTo url ->
  ( model, Navigation.newUrl url )

But that only makes the URL in the address bar change, the user doesn't actually go to the new url... I could use a port and write some simple JavaScript code to call window.location.href = 'newpage.html', I'm just hoping there's a simple standard Elm way to do this.

glennsl
  • 28,186
  • 12
  • 57
  • 75
at.
  • 50,922
  • 104
  • 292
  • 461

6 Answers6

6

What would work for your current situation would be to use a port and force JavaScript to do it for you. This is library agnostic. The reason I would like to suggest doing it this way is that if an <a> tag is not acceptable and you want a Cmd msg, then this will give you exactly that.

I will include a basic example that should fairly easily correlate to what you're doing.

You should create a module that accepts ports or convert one of your current ones to use them by creating a module and adding port to the beginning of the module declaration. You can also just modify an existing module to do this in the same way.

A sample module for this would be

port module OpenWindow exposing (openWindow)

port openWindow : String -> Cmd msg

Now you have your port declaration in your code. You can use it where you want by wrapping it in a function or you can simply call openWindow from your update function when you import it from the module OpenWindow.

Next you should add your port JavaScript code.

In your index.js or your <script> tag where you define the usual

var Elm = require('../Main');
var node = document.getElementById('main');
var app = Elm.Main.embed(node);

or however you do it, simply add

app.ports.openWindow.subscribe(function(newSite) {
    window.open(newSite);
});

You would just add this to your original example by code like

GoTo url ->
  ( model, openWindow "newpage.html" )

Personally, I would not recommend doing this often as this is not really the best way if normally an a [] [] statement would work.

You could more properly probably add an anchor tag to your button and reference it that way.

Note: Additional information about the window.open() function can be found here.

neldridg
  • 176
  • 3
5

Package elm-lang/navigation lets you do this directly these days, with the function load:

GoTo url ->
    ( model, Navigation.load url )
robx
  • 2,221
  • 1
  • 14
  • 31
2

Seems like elm-history's Location.assign achieves the redirection.

It will "load the resource at the provided URL, or provides an error message upon failure". "It does not merely change the URL in the title bar".

Marcelo Lazaroni
  • 9,819
  • 3
  • 35
  • 41
  • 1
    Thank you Marcelo, this appears to be a package that supports what I'm looking for. Though isn't supported with Elm 0.18. – at. Dec 05 '16 at 04:03
2

There is this somewhat dirty hack you could use:
Supply a one-liner of javascript to an Elm style attribute. Using attribute from the Html.Attributes library.

You could make your own helper that does the redirect:

redirectTo : String -> Attribute msg
redirectTo destinationUrl =
  attribute 
    "onclick" 
    ("window.location.href = ' ++ destinationURL ++ "'")

Which you can add to any element like this:

button 
  [ class "mdl-button", redirectTo "https://google.com" ]
  [ text "Click to leave" ]
wintvelt
  • 13,855
  • 3
  • 38
  • 43
0

We're so used to Bootstrap enabling button link styling of anchors, so you question is a good one.

I played around with the Chrome devtools and wrapped a button on the elm-mdl site with a anchor link, and it seemed to redirect as you want.

You might also want to change the title of your question to something like - Link to new webpage from an elm-mdl button - as there is nothing stopping links in elm in general

Simon H
  • 20,332
  • 14
  • 71
  • 128
  • Thank you for the comments. I'll revise the subject line. Though I really wanted to know how to go to a new page from a `Cmd` in Elm. The `button` is just my current use case that made me curious how to implement that without having to create a port. The wrapping of an `a` tag around the button is a good workaround. I had actually just put the `button` in a `form` with `method="get"` and `action="page.html"`, but I get an ugly `?` character in the URL that way. – at. Dec 03 '16 at 01:51
0

This works (in .18), but it is not so pretty:

Make a file in your project called Native/Navigation.js

var _user$project$Native_Navigation = function() {

function setLocation(n)
{
    document.location.href = n;
}

return {
    setLocation: setLocation,
};

}();

Add to your elm-package.json:

"native-modules": true,

In your code:

import Native.Navigation

and return Native.Navigation.setLocation "/wherever" from your update function.

The Javascript function really doesn't behave as a Elm callback should, but since you redirect away from the page that shouldn't be too big of a problem. I guess this could work as a properly published Elm module...

Harmen
  • 669
  • 3
  • 8