Skip to content

Instantly share code, notes, and snippets.

@pdamoc
Last active March 26, 2016 18:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pdamoc/97ca5e1ad605f7e5ebcb to your computer and use it in GitHub Desktop.
Save pdamoc/97ca5e1ad605f7e5ebcb to your computer and use it in GitHub Desktop.
Integrating ports with Elm Architecture

Instructions

  • compile the SendToPort.elm to elm.js
    elm-make SendToPort.elm --output elm.js
  • open SendToPort.html

Observations

The view contains two buttons that send the information to the port in two ways:

  1. by triggering an action that will send the information to JS incapsulated into an Effect.

  2. by directly sending to the mailbox connected to the port.

The port code includes a way to filter the information sent to the mailbox.

The idea behind structuring code like this is that one could chose a strategy to traverse the port and not have to modify the code that sends the information.

import Effects exposing (Never, Effects)
import StartApp
import Task
import Html exposing (..)
import Html.Events exposing (onClick)
type alias Model =
{ text : String
, number : Int
, jsAddress : Signal.Address JSAction}
init : Signal.Address JSAction -> (Model, Effects.Effects Action)
init address = ({text="Nothing", number=0, jsAddress=address}, Effects.none)
update action model =
case action of
TextFromJS str -> ({model|text = str}, Effects.none)
ToJS -> ({model|number = model.number+1}, toJSEffect model.jsAddress model.number)
NoOp () -> (model, Effects.none)
type Action = TextFromJS String | ToJS | NoOp ()
view : Signal.Address Action -> Model -> Html
view address model =
div []
[ button [onClick address ToJS] [text "Increment and send old value to JS"]
, br [] []
, text <| "From JS: " ++ model.text
, br [] []
, text <| "Current Value: " ++ (toString model.number)
, br [] []
, button [onClick model.jsAddress (Number model.number)] [text "Send current value to JS"]
, br [] []
, button [onClick model.jsAddress (Text "Hello from Elm")] [text "Send greeting to JS"]
]
toJSEffect address no =
Signal.send address (Number no)
|> Task.map NoOp
|> Effects.task
app =
StartApp.start
{ init = init toJsMailbox.address
, update = update
, view = view
, inputs = [Signal.map TextFromJS fromJS]
}
main : Signal Html.Html
main =
app.html
port tasks : Signal (Task.Task Never ())
port tasks = app.tasks
type JSAction = Number Int | Text String | NoJSOp
toJsMailbox = Signal.mailbox NoJSOp
intFilter : JSAction -> Maybe Int
intFilter action =
case action of
Number n -> Just n
Text s -> Nothing
NoJSOp -> Nothing
stringFilter : JSAction -> Maybe String
stringFilter action =
case action of
Number n -> Nothing
Text s -> Just s
NoJSOp -> Nothing
port intToJS : Signal Int
port intToJS = Signal.filterMap intFilter 0 toJsMailbox.signal
port stringToJS : Signal String
port stringToJS = Signal.filterMap stringFilter "Default" toJsMailbox.signal
port fromJS : Signal String
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8"><title>Main</title>
<style>html,head,body { padding:0; margin:0; }
body { font-family: calibri, helvetica, arial, sans-serif; }</style>
<script language="javascript" type="text/javascript" src="elm.js"></script>
</head>
<body><div id="main"></div>
<script type="text/javascript">
var div = document.getElementById('main');
var myapp = Elm.embed(Elm.Main, div, {fromJS: "noText"});
myapp.ports.intToJS.subscribe(sendInt);
myapp.ports.stringToJS.subscribe(sendString);
function sendString(string) {
myapp.ports.fromJS.send(string);
}
function sendInt(no) {
myapp.ports.fromJS.send("Old Value: "+no);
}
</script>
</body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment