21

How does one upload a file (image or excel) in Elm?

Can't seem to find any examples.

The answer is fine even if the native code is used. Have seen Data in Elm-Html but it appears files and blobs are not supported. What is the way around this?

ritcoder
  • 3,274
  • 10
  • 42
  • 62

4 Answers4

19

I am the author of the library MisterMetaphor refers to. It's easier to use than he explains though. Take a look at how I set up elm-package.json in the example: https://github.com/simonh1000/file-reader/blob/master/example/elm-package.json - just add "native-modules": true,.

I have written a blog to support the release of the code for 0.18 and show how uploads to e.g. S3 can be done in Elm.

rofrol
  • 14,438
  • 7
  • 79
  • 77
Simon H
  • 20,332
  • 14
  • 71
  • 128
  • 1
    Got to to work by setting native-modules to true, including elm-mimetype package and adding the file-reader's src folder to the source-directories. After that, every thing was straight forward. – ritcoder Feb 29 '16 at 14:22
  • 4
    It can't, because all native /kernel code is now banned – Simon H Nov 02 '18 at 17:44
16

The official way to do it is now https://package.elm-lang.org/packages/elm/file/latest/

This is an addition that came in Elm 0.19.

Now the official Http package supports it as well. Here is an example from https://package.elm-lang.org/packages/elm/http/latest/Http#request

import File
import Http

type Msg = Uploaded (Result Http.Error ())

upload : File.File -> Cmd Msg
upload file =
  Http.request
    { method = "PUT"
    , headers = []
    , url = "https://example.com/publish"
    , body = Http.fileBody file
    , expect = Http.expectWhatever Uploaded
    , timeout = Nothing
    , tracker = Nothing
    }
Marcelo Lazaroni
  • 9,819
  • 3
  • 35
  • 41
6

Use a library like file-reader.

There is a set of pretty comprehensive examples, you can start with this one.

There's a caveat, though. Since this library uses some native code, you can't get it from the official package repo. So you will have to resort to manually installing it.

For this purpose, I wrote this hacky elm-package install replacement. It expects an exact-dependencies.json file in the root directory of your project. You can get this file initially from the elm-stuff directory that elm-package creates when building your project. You then add a reference to the file-reader package to the exact-dependencies.json file like this:

{
    "evancz/elm-effects": "2.0.1",
    "evancz/virtual-dom": "2.1.0",
    "evancz/elm-http": "3.0.0",
    "evancz/start-app": "2.0.2",
    "evancz/elm-html": "4.0.2",
    "elm-lang/core": "3.0.0",
    "simonh1000/file-reader": "1.0.0"
}

You will also need to add a reference to file-reader to your elm-package.json file:

{
    "version": "1.0.0",
    "summary": "helpful summary of your project, less than 80 characters",
    "repository": "https://github.com/user/project.git",
    "license": "BSD3",
    "source-directories": [
        "."
    ],
    "exposed-modules": [],
    "dependencies": {
        "elm-lang/core": "3.0.0 <= v < 4.0.0",
        "evancz/elm-effects": "2.0.1 <= v < 3.0.0",
        "evancz/elm-html": "4.0.2 <= v < 5.0.0",
        "evancz/elm-http": "3.0.0 <= v < 4.0.0",
        "evancz/start-app": "2.0.2 <= v < 3.0.0",
        "simonh1000/file-reader": "1.0.0 <= v < 2.0.0",
    },
    "elm-version": "0.16.0 <= v < 0.17.0"
}

After this, you run the elm-package install replacement and hopefully it will work.

Andrew Gaul
  • 2,296
  • 1
  • 12
  • 19
MisterMetaphor
  • 5,900
  • 3
  • 24
  • 31
  • Cool. I've cloned the repo and will check it out. Will try uploading a form with an image and an excel file to see how it goes. – ritcoder Feb 16 '16 at 20:40
6

The other option to handle file uploads in Elm is to

  • get a base64-encoded value from the FileReader into your Elm app through a port.
  • Then, send that base64-encoded value to your server (e.g. in a JSON body).

A tutorial can be found here https://www.paramander.com/blog/using-ports-to-deal-with-files-in-elm-0-17 (it says it's for Elm 0.17, but it works unchanged in Elm 0.18).

The downsides of this approach are

  • your server needs to base64-decode the files it receives which increases server load a little, and
  • base64-encoding increases the amount of bytes that will go over the wire (compared to a file/blob).

The upside:

  • no need to use a package with native code.

From the Elm Http docs: "Right now it only supports strings, but we will support blobs and files when we get an API for them in Elm."

sabine
  • 301
  • 3
  • 5