5 ms·
It's not much. On the Javascript side, the Elm `app` is like an event emitter where you listen for updates and send it data. var app = Elm.Main.embed(...)
by danneu 10y ago
It's not much.
On the Javascript side, the Elm `app` is like an event emitter where you listen for updates and send it data.
var app = Elm.Main.embed(...)
app.ports.gameState.subscribe((data) => ...)
app.ports.tileClick.send([x, y])
On the Elm side, you subscribe to incoming ports and map them into Msgs. And you emit to ports with Cmds from your update function.
-- Ports.elm
port gameState : Json.Encode.Value -> Cmd msg // Outgoing
port tileClicked : ((Int, Int) -> msg) -> Sub msg // Incoming
-- Main.elm
update msg model =
case msg of
Tick ->
-- Define `encode` to Json.Encode the game state
(model, Ports.gameState (GameState.encode data))
TileClicked (x, y) ->
-- Handle tile clicks sent in from Javascript
subscriptions model =
Ports.tileClicked TileClicked
- david-given 10y agoYes, but just like the ones in the docs, that's a nearly trivial example, and so doesn't demonstrate the complexity. What I'm concerned about is the case when I want to call a Javascript function from deep down inside, say, a computation function. Do I have to split my computation into two halves, one which sends the event which calls the Javascript function, and another which receives the result of the function? How do I pass the in-progress computation state from one to the other? Normally in a functional language I'd get around this by simply passing a function reference into the Javascript function which the handler would then call, so allowing me to have both parts of the computation in the same place and operating on the same data, but apparently in Elm function references don't survive being passed through Javascript. Plus, each port only has a single incoming event, so if I'm calling the Javascript function from multiple places I can imagine it can very easily turn into a labyrinth of state passing code. How do you avoid this?
- danneu 10y agoSome interactions with 3rd party libraries (like rendering stuff, leaflet.js, pixi.js) fall along natural event-driven faults, like the game update tick finishing, something managed by Elm being clicked, that sort of thing. In these cases, ports (events) are the obvious fit. Then there's synchronous 3rd party library stuff where you just want to execute a Javascript function, like a math function that you aren't going to reimplement in Elm. In that case, I wrap the function with a native module and call it like an Elm function. Since you talk of computation, is this what you're talking about? The Elm community highly discourages native modules. For one thing, they aren't very well documented and the API seems to have recently changed. But I'm not sure what the alternative is.
- david-given 10y agoAh, right --- I have heard of native modules, but only in the context of things I shouldn't using. I'll look more closely. Ta!