Drag & Drop Images with Preview using Stimulus Outlets
In a previous article I explored a way to preview images before uploading with Stimulus.
I now want to extend its functionality by adding drag & drop. Along the way I am also using Stimulus outlets to tie the two functionalities together. Showcasing more advanced use of small Stimulus controllers.
I assume you walked through all the steps of the previous mentioned article.
Let’s start with the HTML. It’s using the other HTML with just a few attributes added.
<div data-controller="image-preview dropzone" data-action="dragover->dropzone#dragOver dragleave->dropzone#dragLeave drop->dropzone#drop">
<img data-image-preview-target="canvas" hidden class="object-cover size-48">
<input type="file" accept="image/*" data-image-preview-target="source" data-dropzone-target="input" data-action="image-preview#show" hidden>
</div>
Let’s create the dropzone_controller.js.
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["input"];
dragOver(event) {
event.preventDefault();
}
dragLeave(event) {
event.preventDefault();
}
drop(event) {
event.preventDefault();
this.#updateInputField(event.dataTransfer.files[0]);
}
}
All these methods do is preventing the default event when these actions are invoked. The drop() function also calls the private function this.#updateInputField(). Let’s add it.
export default class extends Controller {
// …
// private
#updateInputField(file) {
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
this.inputTarget.files = dataTransfer.files;
}
// …
}
This will inject the dropped image into the inputTarget field. And just like that you can drag and drop images onto the element. 🤯
Preview images with outlets
An important part is missing though… the image isn’t showing which looks like a bug. Luckily with the image_preview_controller.js already done. This is a simple exercise.
First tweak the HTML with the following attributes:
<div data-controller="image-preview dropzone" data-dropzone-image-preview-outlet="#image-preview" data-action="dragover->dropzone#dragOver dragleave->dropzone#dragLeave drop->dropzone#drop" id="image-preview>
<img data-image-preview-target="canvas" hidden class="object-cover size-48">
<input type="file" accept="image/*" data-image-preview-target="source" data-dropzone-target="input" data-action="image-preview#show" hidden>
</div>
Added:
-
data-dropzone-image-preview-outlet="#image-preview"; -
id="image-preview".
Now two lines are needed in the dropzone_controller.js.
export default class extends Controller {
static outlets = ["image-preview"];
// …
drop(event) {
// …
this.imagePreviewOutlet.show();
// …
}
// …
}
Now when you drop an image it fires the show() function on the image_preview_controller.js (created in the previous article). 🥳
I like to use small Stimulus controllers like these that work great together.
Need an alternative to S3 to store your images?
Rails Designer has this Stimulus controller packaged with a few extras added! Get your copy today.
Want to read me more?
-
ActiveStorage Direct Upload with Stimulus
ActiveStorage's DirectUpload feature allows files to be directly uploaded to your Cloud's storage without touching your app's server. -
Preview an Image Before Upload with Hotwire/Stimulus
Learn about JavaScript's FileReader interface to preview user images before they are upload with Hotwire/Stimulus. -
Communicating between Stimulus Controllers using Outlets API
Sometimes one Stimulus controller is not enough. Use the Outlets API to have multiple Stimulus contollers communicating with each other.
Over to you…
What did you like about this article? Learned something knew? Found something is missing or even broken? 🫣 Let me (and others) know!
Comments are powered by Chirp Form
{{comment}}