Skip to content

Instantly share code, notes, and snippets.

@zgohr
Last active July 17, 2017 02:07
Show Gist options
  • Save zgohr/265123ae03c909f466d1a8960958b890 to your computer and use it in GitHub Desktop.
Save zgohr/265123ae03c909f466d1a8960958b890 to your computer and use it in GitHub Desktop.
Binary file uploads in Elm 0.18
<html>
<head>
<style>
html {
background: #F7F7F7;
color: red;
}
</style>
</head>
<body>
<script>
var app = Elm.Main.fullscreen()
app.ports.fileUpload.subscribe(function(id) {
var node = document.getElementById(id);
if (node === null) {
return;
}
var file = node.files[0];
var reader = new FileReader();
reader.onload = (function(event) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/upload/endpoint");
var formData = new FormData();
formData.append("file", file);
xhr.send(formData);
xhr.onload = function(e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
app.ports.fileUploaded.send(true);
} else {
app.ports.fileUploaded.send(false);
}
}
}
});
reader.readAsArrayBuffer(file);
});
</script>
</body>
</html>
{-
Very basic single-file binary file uploading via Elm port.
One area for improvement is in error handling. Since I only care if a file
uploads successfully, that's all I'm passing in the callback port.
One known issue is since we execute the port on "change", uploading
the same file multiple times in a row will not have any affect since
the DOM element doesn't "change" if the same file gets selected.
-}
port module Main exposing (..)
import Html exposing (Html, text)
import Html.Attributes exposing (type_, id, style, class)
import Html.Events exposing (on)
import Json.Decode as Decode
port fileUpload : String -> Cmd msg
port fileUploaded : (Bool -> msg) -> Sub msg
type Msg
= FileSelected
| FileUploaded Bool
type alias Model =
{ fileInputId : String
}
init =
( Model "FileInputId", Cmd.none )
view model =
Html.div []
[ Html.label [ class "btn btn-primary" ]
[ Html.input
[ type_ "file"
, id model.fileInputId
, style [ ( "display", "none" ) ]
, on "change" (Decode.succeed FileSelected)
]
[]
, text "Upload"
]
]
update msg model =
case msg of
FileSelected ->
( model, fileUpload model.fileInputId )
FileUploaded True ->
-- obviously, set some state notifying success
( model, Cmd.none )
FileUploaded False ->
-- obviously, set some state notifying failure
( model, Cmd.none )
subscriptions model =
fileUploaded FileUploaded
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment