Drag & Drop Images with Preview using Stimulus Outlets
Rails Designer
Posted on September 26, 2024
This articles was originally published on Rails Designer
In a previous article I explored a way to preview images before upload with Stimulus.
I know want to extend its functionality by adding a 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 show which looks like a bug. Luckily with the image_preview_controller.js already done. This is a simple exercise.
First tweak the HTML by adding 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. 🥳
I like to use small Stimulus controllers like these that work great together.
Rails Designer has this Stimulus controller packaged with a few extras added. Get your copy today.
Posted on September 26, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.