Skip to content

Instantly share code, notes, and snippets.

@cseelus
Last active May 1, 2019 16:12
Show Gist options
  • Save cseelus/63baa4f46f6f0ae0c4630a3987022f97 to your computer and use it in GitHub Desktop.
Save cseelus/63baa4f46f6f0ae0c4630a3987022f97 to your computer and use it in GitHub Desktop.
Uploading files automatically with ActiveStorage
import { DirectUpload } from 'activestorage'
// See DirectUploadController from Rails Active Storage source
export class CustomUploader {
constructor(input, file) {
this.input = input
this.file = file
this.directUpload = new DirectUpload(this.file, this.url, this)
this.dispatch("initialize")
}
start() {
const hiddenInput = document.createElement("input")
hiddenInput.type = "hidden"
hiddenInput.name = this.input.name
hiddenInput.classList.add('cache')
this.input.insertAdjacentElement("beforebegin", hiddenInput)
this.dispatch("start")
this.directUpload.create((error, attributes) => {
if (error) {
hiddenInput.parentNode.removeChild(hiddenInput)
this.dispatchError(error)
} else {
hiddenInput.value = attributes.signed_id
}
this.dispatch("end")
// callback(error)
})
}
uploadRequestDidProgress(event) {
const progress = event.loaded / event.total * 100
if (progress) {
this.dispatch("progress", { progress })
}
}
get url() {
return this.input.getAttribute("data-direct-upload-url")
}
dispatch(name, detail = {}) {
detail.file = this.file
detail.id = this.directUpload.id
return dispatchEvent(this.input, `direct-upload:${name}`, { detail })
}
dispatchError(error) {
const event = this.dispatch("error", { error })
if (!event.defaultPrevented) {
alert(error)
}
}
directUploadWillStoreFileWithXHR(xhr) {
this.dispatch("before-storage-request", { xhr })
xhr.upload.addEventListener("progress", event => this.uploadRequestDidProgress(event))
}
}
function dispatchEvent(element, type, eventInit = {}) {
const { disabled } = element
const { bubbles, cancelable, detail } = eventInit
const event = document.createEvent("Event")
event.initEvent(type, bubbles || true, cancelable || true)
event.detail = detail || {}
try {
element.disabled = false
element.dispatchEvent(event)
} finally {
element.disabled = disabled
}
return event
}
import { CustomUploader } from 'custom_uploader'
// Handle change, e.g. User attaches a file
const inputs = Array.from(document.querySelectorAll('.custom-file-input'))
inputs.forEach(input => {
input.addEventListener('change', event => {
Array.from(input.files).forEach( file => {
const uploader = new CustomUploader(input, file)
uploader.start(file)
})
// clear the selected files from the input
input.value = null
})
})
addEventListener('direct-upload:initialize', event => {
// … see https://guides.rubyonrails.org/active_storage_overview.html#example how to use the callbacks for displaying progress
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment