evancz/local-channel

Channels that allow modular and self-contained view code


License
BSD-3-Clause
Install
elm-package install evancz/local-channel 1.0.0

Documentation

local-channel

The general recommendation for making Elm applications modular is to write as much code as possible without signals. We should be primarily be using plain old functions. A typical component will have roughly this API:

-- A model of our component
type alias Model = { ... }

-- Different ways we can update our model
type Update = ...

-- A function to actually perform those updates
step : Update -> Model -> Model

-- A way to view our model on screen and to trigger updates
view : Signal.Channel Update -> Model -> Html

One challenge seems to be that writing a view often requires hooking up to some signal channel. The hard question seems to be, how can we have all our different components reporting to a signal channel in a modular way? Local channels answer this question!

Usage Example

Say we want to model an app that has a search component and a results component. Ideally those components can be written by different people on different teams with minimal amounts of coordination or dependency between their code. Local channels allow them to write self-contained modules that expose view functions with the following types.

  • Search.view : LocalChannel Search.Update -> Search.Model -> Html
  • Results.view : LocalChannel Results.Update -> Results.Model -> Html

Once you have those building blocks, you can wire them together in a larger application like this:

import Signal
import LocalChannel as LC

type alias Model =
    { search : Search.Model
    , results : Results.Model
    , ...
    }

type Update
    = NoOp
    | SearchUpdate Search.Update
    | ResultsUpdate Results.Update
    | ...

updateChannel : Signal.Channel Update
updateChannel =
    Signal.channel NoOp

view : Model -> Html
view model =
    div [] [
      Search.view (LC.create SearchUpdate updateChannel) model.search,
      Results.view (LC.create ResultsUpdate updateChannel) model.results
    ]

In this world, we can create the true Signal.Channel at the very root of our application with all the other signals. Our components do not need to know anything about that though, they just need to ask for a local channel to report things to.