As a quick note to anyone struggling with how to perform app wide
inter-component communication in elm 0.17 (e.g. anyone building a
non-trivial SPA), here is one simple way to setup pubsub style
communication using Elm Ports and Subscriptions.
In this example, ChildOne will broadcast a message that ChildTwo is
listening for.
Ports.elm
*port* module Ports exposing (..)
-- dispatchSomeMessage will create a command with a
-- string payload representing an important message
-- to broadcast to listening components.
port *dispatchSomeMessage* : String -> Cmd msg
-- receiveSomeMessage is the port which our components
-- subscribe to receive the dispatched message
port *receiveSomeMessage* : (String -> msg) -> Sub msg
The Ports.elm file contains all of the port specifications in the app. In
this case it defines a two ports: one port for dispatching a message, and
another for receiving a message. The module declaration at the top of the
file must be preceded by "port".
index.js
var app = Elm.Main.fullscreen();
app.ports.*dispatchSomeMessage*.subscribe(function(msg) {
app.ports.*receiveSomeMessage*.send(msg);
});
This is where the behaviour of all ports are defined in javascript. In this
case the dispatchSomeMessage function is receiving a msg argument from Elm,
and then quickly sending that message back into Elm through the
receiveSomeMessage port.
ChildOne.elm
module ChildOne exposing (..)
import Ports exposing (..)
import Html exposing (Html, button, text)
import Html.Events exposing (onClick)
type alias Model = String
type Msg
= Click
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Click ->
( model, *dispatchSomeMessage "Hello World!"* )
view : Model -> Html Msg
view model =
button [ onClick Click ] [text "Click Me"]
ChildOne dispatches the message "Hello World!" through the
dispatchSomeMessage port when a button in the view is clicked. The message
is then routed from the dispatchSomeMessage port, directly back into the
receiveSomeMessage port as defined in index.js
ChildTwo.elm
module ChildTwo exposing (..)
import Ports exposing (..)
import Html exposing (Html, text)
type alias Model =
{ message : String }
type Msg
= ChangeMessage String
subscriptions : Model -> Sub Msg
subscriptions model =
*receiveSomeMessage **ChangeMessage*
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ChangeMessage msg ->
({ model | message = msg }, Cmd.none )
view : Model -> Html Msg
view model =
text model.message
ChildTwo subscribes a ChangeMessage tag to the 'receiveSomeMessage' port.
When the port receives the "Hello World" message from ChildOne, ChildTwo
updates its models message, and re-renders the view.
Main.elm
module Main exposing (..)
import ChildOne
import ChildTwo
type alias Model =
{ childOneModel : ChildOne.model
, childTwoModel : ChildTwo.model
}
-- ..init func. nothing special here.
type Msg
= ChildOneMsg ChildOne.Msg
| ChildTwoMsg ChildTwo.Msg
subscriptions : Model -> Sub Msg
subscriptions model =
* Sub.batch*
* [ Sub.map ChildOneMsg (ChildOne.subscriptions
model. childOneModel)*
* , Sub.map ChildTwoMsg (ChildTwo.subscriptions
model. childTwoModel)*
* ]*
-- .. update function. nothing special here.
main : Program Never
main =
Html.App.program
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
Main.elm batches the subscriptions defined in child components. That's all
there is to it. Nice and clean inter-component communication.
--
You received this message because you are subscribed to the Google Groups "Elm
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.