# Package: pdamoc/elm-ports-driver

**URL:** <https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645>\
**Category:** Request Feedback\
**Created:** [February 7, 2018, 1:51pm UTC](https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645 "2018-02-07T13:51:25Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [February 7, 2018, 1:51pm UTC](https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645/1 "2018-02-07T13:51:25Z")

</div>

Hi there,

I have created a proof of concept of an idea I had for a long time.

[http://package.elm-lang.org/packages/pdamoc/elm-ports-driver/latest](http://package.elm-lang.org/packages/pdamoc/elm-ports-driver/latest)

The basic idea is to use convention and encapsulate frequently used JS code inside a `driver` that can receive commands from Elm and can reply to Elm with the results of certain commands (if there is such a need).

Right now it is only a minimal proof of concept that I needed for a project that needs the `FileReader` API. I have also added a command to change the title and a command to mount some CSS in the head (they were low hanging fruits). All three pieces are demonstrated in the `example` folder.

For the next version I’m planning to add `localStorage` support.

Please take a look and provide feedback.

---

<div class="post-metadata">

**Author:** ![norpan](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/norpan/32/548_2.png) [@norpan](https://discourse.elm-lang.org/u/norpan)\
**Post date:** [February 7, 2018, 3:02pm UTC](https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645/2 "2018-02-07T15:02:53Z")

</div>

I think it’s a great proof of concept! Let me summarize the things I said on slack

- The `Driver` type should be opaque, with its fields being functions that take a `Driver` argument
- The `Msg` type should be opaque, with the `File` constructor instead being a function `file : Msg -> Maybe (String, String, Contents)`
- Perhaps allow for the names of ports to be specified in `elm_ports_driver.install()`

For file inputs

- Selection of multiple files
- Chunked file reading

---

<div class="post-metadata">

**Author:** ![mcordova47](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mcordova47/32/559_2.png) [@mcordova47](https://discourse.elm-lang.org/u/mcordova47)\
**Post date:** [February 8, 2018, 5:39am UTC](https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645/3 "2018-02-08T05:39:56Z")

</div>

This looks really cool! Just had a small suggestion.

I think it would be helpful to at least have a version of the file commands that don’t rely on an input id and instead expect a `File` object. So the functions would be of type `Value -> Cmd msg` and the user would have to decode a file from an event. I’ve had to do this to implement a drag and drop file uploader, since there is no input element with file info in that case.

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [February 8, 2018, 6:01am UTC](https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645/4 "2018-02-08T06:01:39Z")

</div>

> [@mcordova47](#):
>
> I’ve had to do this to implement a drag and drop file uploader, since there is no input element with file info in that case.

Do you have some open source code that I can look at that functionality?

---

<div class="post-metadata">

**Author:** ![mcordova47](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mcordova47/32/559_2.png) [@mcordova47](https://discourse.elm-lang.org/u/mcordova47)\
**Post date:** [February 8, 2018, 12:10pm UTC](https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645/5 "2018-02-08T12:10:15Z")

</div>

Sure thing, I used it in this project: [https://github.com/mcordova47/payback](https://github.com/mcordova47/payback).

Here are the relevant snippets:

Main.elm \> update:

```
UploadFile file ->
    ( { model | dragging = False }, Ports.upload file )

```

Decoder:

```
dropEventDecoder : Decoder Value
dropEventDecoder =
    Decode.at ["dataTransfer", "files", "0"] Decode.value

```

File Drag/Drop Element:

```
fileDrop : Maybe String -> Bool -> Html Msg
fileDrop message dragging =
    Html.div
        [ Events.onWithOptions "drop"
            { stopPropagation = False, preventDefault = True }
            (Decode.map UploadFile dropEventDecoder)

```

Ports.elm:

```
port upload : Value -> Cmd msg

```

index.js:

```
app.ports.upload.subscribe(file => {
  const fileReader = new FileReader()
  fileReader.onload = () => app.ports.readFile.send(fileReader.result)
  fileReader.readAsText(file)
})
```

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [February 12, 2018, 3:09pm UTC](https://discourse.elm-lang.org/t/package-pdamoc-elm-ports-driver/645/6 "2018-02-12T15:09:29Z")

</div>

I have just published version 3.0.0 of the package (npm version 2.1.0)

What I changed:

- rather than have a monolith command processor in JS, I have made it so that `install` receives a list of “plugins” where each knows how to handle one or more messages. I believe that this will help with DCE.

- in Elm, instead of having one driver record now there are a commands creators that take a config object.

- the `subscriptions` takes the `config` and a list of message decoders and if the incoming message does not matches any of them, it will return the fail msg.

- the `onFile` replaces `onFileChange`. The msg creator receives a `FileRef` for the file selected. `FileRef` is then used to request the read. `FileRef` is just a `Value` so, `FileRef` from other sources (the above drop example) should be just fine.

I have also implemented the `localStorage` support.

Multiple file support and chunked file read are delayed for a future version.

If any of you wants to help in any way, PR are more than welcome.

The first priority is a stable convention for how to do this ports driver. Once we have this, extension should be easier. I think this version is in much better shape than the first version.

Please take a look and provide feedback as to how I can improve this.
