Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading global JavaScript variable from Elm

Tags:

javascript

elm

I'm currently building a small component of a web app in Elm. The elm component is compiled to a JavaScript file, loaded and then mounted on a DOM node. It should then read a config object from window.config. (This is not something I can change.)

How can I e.g. read a string from window.config.title to use in my Elm component? I've looked at ports, but it seems to require me to modify the generated JavaScript or wrap something around it. Is that the only option? If so, how would I simply read the value of a variable?

like image 481
beta Avatar asked Dec 15 '22 05:12

beta


1 Answers

Edit: Updated to Elm 0.19

If your configuration does not change over the lifetime of your app, you will probably be best served by using Browser.element or Platform.worker.

This allows for your main function to accept a single value from Javascript during initialization. That single value can be a simple javascript object or it can even contain nested properties. The important thing is defining its shape inside Elm.

Let's say your javascript configuration looks like this:

<script>
  window.options = {
    foo: 123,
    nested: { bar: "abc" }
  };
</script>

In order to be able to pass that into your Elm file, you can define a matching shape like this:

type alias Flags =
  { foo : Int
  , nested : { bar : String }
  }

Now you can use Browser.element or Platform.worker in your Elm file like this, defining an init function that takes Flags as an argument:

import Html exposing (..)
import Browser
import String

main =
  Browser.element
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

init : Flags -> (Model, Cmd Msg)
init flags =
  ( { introText = String.concat
    [ "foo is "
    , String.fromInt flags.foo
    , " and nested.bar is "
    , flags.nested.bar
    ]
    },
    Cmd.none
  )

The last piece of the puzzle is to pass your Javascript configuration option to Elm during initialization. Your html and javascript should look something like this (the relevant portion is in passing window.options as the flags parameter of init()):

<body>
  <div id="myContainer"></div>
  <script src="Main.js"></script>
  <script>
    var app = Elm.Main.init( {
      node: document.getElementById("myContainer"),
      flags: window.options
    } );
  </script>
</body>

Here is a working example on ellie-app.

like image 191
Chad Gilbert Avatar answered Feb 12 '23 13:02

Chad Gilbert