A short introduction to Ports and Flags in Elm
Tags: elm, programming, tutorial, javascript
Published: 2019-08-27 11:38:55

---
title: A short introduction to Ports and Flags in Elm
published: true
tags: elm,programming,tutorial,javascript
canonical_url: https://lengrand.fr/a-short-introduction-to-ports-and-flags-in-elm/
---

 ![A short introduction to Ports and Flags in Elm](https://lengrand.fr/content/images/2019/07/1_o-gIsoWXAhk-oZoz-WSdXg.jpeg)

**[TLDR: Full minimal working example with ports and flags here](https://github.com/jlengrand/elm-ports), with a live demo [here](https://elm-ports.netlify.com/).**

It's been a couple years now that I've been following the developments of **[Elm](https://elm-lang.org/)**. I went to [Elm Europe](https://2019.elmeurope.org) two years in a row now, but somehow my actual experience with the language is still very limited and I've only been writing a couple basic prototypes with it.

Elm is, as Wikipedia describes is better than I would

> a domain-specific programming language for declaratively creating web browser-based graphical user interfaces. Elm is purely functional, and is developed with emphasis on usability, performance, and robustness.

I am no expert at functional programming, but Elm surely made me better at it. Elm is 'watch a movie at the same time and be sure your stuff will not be buggy' kind of good. It is pure and has a huge focus on compiler error readability. What it is means in effect is, if your stuff compiles, it's probably gonna be working as expected.

One of the things that intimidated so far though was the Javascript Interoperability. Because Elm is pure, the only way to interact with the bad, impure Javascript world is to push it to the borders and describe interfaces with it : Namely ports and flags. That seemed like a bridge too far for me until yesterday.

## Ports and Flags

At its core, Elm is pure. What that means is that it is pretty much literally impossible to generate and handle side-effects when writing basic Elm. You cannot do anything that may fail, like getting the time from the system, or make an HTTP call. It has huge benefits. Any code you write cannot, by design, generate any runtime exceptions.

Of course, this is pretty limiting and one needs to interact with the world to build an application. The world is simply not pure. This is why Elm allows you to interact with the impure world via Flags, and Subscriptions. And you can generate your own interfaces with the outside using Ports that will generate trigger those subscriptions.

The best thing you should start with if you want to know more about ports and flags is to [read the documentation by the creator of the language himself](https://guide.elm-lang.org/interop/ports.html).

Essentially,

- **Ports** allow you to define an interface to and from Javascript. Because it is Command and Subscription based, those interactions will appear pure to Elm.
- **Flags** are a way to set some of the Elm model using data coming from Javascript at the very beginning of the instantiation of the Model.

I read those pages carefully, but some of the actual details were still quite blurry to me because there is no full working example there. This is what this post intends to fix. [You can find the full working repository here](https://github.com/jlengrand/elm-ports).

## Sending data Elm -> Javascript using Ports

We will be doing the simplest thing possible : Sending some message to Javascript every time the user will be pressing a button. We will prove reception of the message using a `console.log` statement.

We first need to indicate that our Elm module will contain ports :

<!--kg-card-begin: markdown-->
```
port module Main exposing (Model, Msg(..), init, main, update, view)

```
<!--kg-card-end: markdown-->

And then define our port. It will take some JSON encoded value as input, and generate a Command. Elm will know how to transform that Command into the Javascript world.

<!--kg-card-begin: markdown-->
```
port sendStuff : Json.Encode.Value -> Cmd msg

```
<!--kg-card-end: markdown-->

The last thing we need is a way to trigger that method. We can do it multiple ways, but in our case we will create a `SendData` message that will be triggered on button click.

<!--kg-card-begin: markdown-->
```
type Msg
    = SendData

```
<!--kg-card-end: markdown-->

and finally later in our view we trigger the message in our button

<!--kg-card-begin: markdown-->
```
button [onClick SendData] [text "Send some data"]

```
<!--kg-card-end: markdown-->

We're set! Now, we need to connect the Javascript side of things to receive our messages :).

<!--kg-card-begin: markdown-->
```
app.ports.sendStuff.subscribe(data => {
  console.log(JSON.stringify(data));
});

```
<!--kg-card-end: markdown-->

And that's it! Let's test it!

<!--kg-card-begin: image-->

![A short introduction to Ports and Flags in Elm](https://lengrand.fr/content/images/2019/07/ScreenRecording2019-07-28at4.gif)<figcaption>Sending data to javascript using ports</figcaption>

<!--kg-card-end: image-->
## Sending data Javascript -> Elm using Ports

The process is similar than the last step, but just a little more complex.

First, we define our port

<!--kg-card-begin: markdown-->
```
port receiveStuff : (Json.Encode.Value -> msg) -> Sub msg

```
<!--kg-card-end: markdown-->

Here, `receiveStuff` is **a function that takes a function** that takes a JSON encoded value as an input and returns something, and returns a Subscription with a payload. So we will have to use function composition somehow.

Because we receive JSON payload, we will have to use a Decoder. I will not explain this in details here, [you can read more about Decoders here](https://guide.elm-lang.org/effects/json.html).

My payload is of form `{value: Int}` so the following decoder will be enough:

<!--kg-card-begin: markdown-->
```
valueDecoder : Json.Decode.Decoder Int
valueDecoder =
    Json.Decode.field "value" Json.Decode.int

```
<!--kg-card-end: markdown-->

This allows us to create our Subscription:

<!--kg-card-begin: markdown-->
```
subscriptions : Model -> Sub Msg
subscriptions model =
    receiveStuff (Json.Decode.decodeValue valueDecoder >> Received)

```
<!--kg-card-end: markdown-->

where our port gets the function that takes JSON in, and returns a payload as expected.

In our subscription, we defined `Received`. It is a message that will contain the result of our unmarshalled JSON. It can either be successful, or have failed. This lead to the `slightly` more complex code that handles errors:

<!--kg-card-begin: markdown-->
```
type Msg
    = ...
    | Received (Result Json.Decode.Error Int)

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ...
        
        Received result ->
            case result of
                Ok value ->
                    ( { model | counter = value }, Cmd.none )

                Err error ->
                    ( { model | error = Json.Decode.errorToString error }, Cmd.none )

```
<!--kg-card-end: markdown-->

The interesting line is where we set our internal counter to the new value.

The last thing we have to do in Elm is make our counter visible. We do this in the view

<!--kg-card-begin: markdown-->
```
h2 [] [text <| String.fromInt model.counter]

```
<!--kg-card-end: markdown-->

Alright, the only thing left to do is to send the data from Javascript. For the sake of the demonstration, we will use `setInterval` to increase our counter once a second and periodically send the data to Elm.

<!--kg-card-begin: markdown-->
```
let counter = 1;
setInterval(() => {
  counter += 1;
  console.log(JSON.stringify(counter));
  app.ports.receiveStuff.send({ value: counter });
}, 1000);

```
<!--kg-card-end: markdown-->

Let's test!

<!--kg-card-begin: image-->

![A short introduction to Ports and Flags in Elm](https://lengrand.fr/content/images/2019/07/trim2.gif)<figcaption>Receiving data from Javascript using ports</figcaption>

<!--kg-card-end: image-->
## Setting initial model values in Elm using Flags

One of the things that we can remark from our last example is that in our application, **our counter jumps from 0 to 2** , without going through 1.

This is due to the fact that in our init method we chose to set the initial counter to 0. In effect, Elm initiates the whole model and returns a view, before the ports actually start being activated. **This lead to us missing the initial 1 value of the counter in Javascript.**

We can fix this using flags, so that Elm becomes aware of our initial value of the counter **before** instantiation.

The changes are relatively minimal. First, we will define a type alias that will describe in what form the data will be given to Elm. Because we send the data as such : `{value: 1}`, the following code will be sufficient :

<!--kg-card-begin: markdown-->
```
type alias Flags =
    { value : Int
    }

```
<!--kg-card-end: markdown-->

Then, we make our init function aware of this input, and we take it into account when creating our model. Our init method now takes Flags as extra input, instead of an empty tuple:

<!--kg-card-begin: markdown-->
```
init : Flags -> ( Model, Cmd Msg )
init flags =
    ( { counter = flags.value, error = "No error" }, Cmd.none )

```
<!--kg-card-end: markdown-->

Well, and that's it. Now, we simply have to share our initial value with Elm in our Javascript using the flags argument :

<!--kg-card-begin: code-->
```
let counter = 1;

const app = Elm.Main.init({
  node: document.getElementById("root"),
  flags: { value: counter }
});

```
<!--kg-card-end: code-->

Let's see if that gives us satisfaction!

No more initial 0, and no more jump. That's what success looks like!

<!--kg-card-begin: image-->

![A short introduction to Ports and Flags in Elm](https://lengrand.fr/content/images/2019/07/trimlast.gif)<figcaption>Setting initial values using Flags</figcaption>

<!--kg-card-end: image-->
## Final words

This post is lengthier than I would like, but I hope the extra information is useful. All in all,[the complete code sample](https://github.com/jlengrand/elm-ports/blob/master/src/Main.elm) is just 100 lines of code so it should be convenient to read.

[You can try the demo online here.](https://elm-ports.netlify.com/)

It took me a couple hours to really get into the flow of ports, but they really open up a whole world of possibilities for me now. No need to search for integration with libraries any more (for example firebase), since I can create my own. And all of that while staying purely functional. Pretty handy!

Of course, suggestions are always welcome. Hit me up [@jlengrand](https://twitter.com/jlengrand), or simply on the G[ithub](https://github.com/jlengrand/elm-ports) repo.