Javascript Interop
Javascript interaction happens through something called ports, which are boundaries that you define between your Gren program, where the compiler can guarantee safety and correctness, and Javascript, where it can’t.
Browser Ports
To start using ports in the browser, you’ll need a program defined with
Browser.element
,
Browser.document
, or
Browser.application
.
Change your module to a port module
:
module Main exposing (main)port module Main exposing (main)
Define your incoming and outgoing ports.
Here we’re using String
as the data exchange format, but you may want to use JSON for more power and control.
See Json.Decode
and Json.Encode
.
port toJs : String -> Cmd msgport fromJs : (String -> msg) -> Sub msg
Use commands to send outgoing messages:
init : {} -> { model : Model, command : Cmd Msg }init _ = { model = { message = "" } , command = toJs "Hello from Gren!" }
Use subscriptions to receive incoming messages:
type Msg = MessageReceived String
update : Msg -> Model -> { model : Model, command : Cmd Msg }update msg model = when msg is MessageReceived message -> { model = { model | message = message } , command = Cmd.none }
subscriptions : Model -> Sub Msgsubscriptions _ = fromJs MessageReceived
Compile your program to a javascript file:
gren make src/Main.gren --output=main.js
Create an html file that starts your program like this:
<html><head> <script src="main.js"></script></head><body> <div id="myapp"></div> <script> var app = Gren.Main.init({ node: document.getElementById('myapp'), }); // receiving messages from gren: app.ports.toJs.subscribe(function(message) { alert(message); }); // sending messages to gren: app.ports.fromJs.send("Hello from JS!"); </script></body></html>
Node Ports
To use ports in a node program, you’ll need to define it with
Node.defineProgram
like we did in the webserver section of the book.
Then define and use your ports in Gren the same way as described in the browser section above.
Then compile it with an explicit output target:
gren make src/Main.js --output=main.js
Giving the target a .js
extension tells the compiler that you want a module to be included in other javascript instead of a program that runs directly.
That lets us wire up the ports in a new Javascript file that looks like this:
const main = require("./main.js");const app = main.Gren.Main.init({});
// receiving data from gren:app.ports.toJs.subscribe(function(data) { console.log(`Got data from Gren: ${data}`);});
// sending data to gren:app.ports.fromJs.send("Hello from JS!");
Now you can run it with node:
node index.js