JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://raw.githubusercontent.com/lhorie/mithril.js/components/mithril.js"></script>
CSS
.uploader {border:1px dashed #888;height:100px;}
JavaScript
var Uploader = {
upload: function(options) {
var formData = new FormData
for (var key in options.data) {
for (var i = 0; i < options.data[key].length; i++) {
formData.append(key, options.data[key][i])
}
}
//simply pass the FormData object intact to the underlying XMLHttpRequest, instead of JSON.stringify'ing it
options.serialize = function(value) {return value}
options.data = formData
return m.request(options)
},
serialize: function(files) {
var promises = files.map(function(file) {
var deferred = m.deferred()
var reader = new FileReader
reader.readAsDataURL()
reader.onloadend = function(e) {
deferred.resolve(e.result)
}
reader.onerror = deferred.reject
return deferred.promise
})
return m.sync(promises)
},
controller: function(args) {
this.noop = function(e) {
e.preventDefault()
}
this.update = function(e) {
e.preventDefault()
if (typeof args.onchange == "function") {
args.onchange([].slice.call((e.dataTransfer || e.target).files))
}
}
},
view: function(ctrl, args) {
return m(".uploader", {ondragover: ctrl.noop, ondrop: ctrl.update})
}
}
//usage demo 1: standalone multipart/form-data upload when files are dropped into the component
var Demo1 = {
controller: function() {
return {
upload: function(files) {
Uploader.upload({method: "POST", url: "/echo/json/", data: {files: files}}).then(function() {
alert("uploaded!")
})
}
}
},
view: function(ctrl) {
return [
m("h1", "Uploader demo"),
m("p", "Drag and drop a file below. An alert box will appear when the upload finishes"),
m.component(Uploader, {onchange: ctrl.upload})
]
}
}
m.mount(document.body, Demo1)