Our drag and drop from episode 51 is functional, but it isn't very clear how to use it.
In this episode we'll combine the dragEnter and dragLeave events with some css in order to improve the experience and make it more obvious when you're supposed to drop your file.
Links
Code
//stylesheets.css.scss
.dropzone.uploader {
width: 300px;
height: 200px;
background-color: grey;
position: relative;
&.is-dragging {
background-color: #9D9;
border: 4px solid #191;
border-radius: 4px;
}
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
//components/file-upload/component.js
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'div',
classNames: ['uploader', 'dropzone'],
isDragging: Ember.computed.gt('dragCounter', 0),
classNameBindings: ['isDragging'],
dragCounter: 0,
dragEnter() {
this.incrementProperty('dragCounter')
},
dragLeave(){
this.decrementProperty('dragCounter')
},
dragOver(event) {
event.preventDefault()
},
drop(event) {
event.preventDefault()
this.set('dragCounter', 0)
var file = event.dataTransfer.files[0]
this.sendAction('fileInputChanged', file)
}
});
//post/edit-fields/template.hbs
{{#file-upload fileInputChanged="receiveFile"}}
<img id="preview-image" src="{{model.thumbnailImage.thumbnail_image.url}}" class="small-image" />
{{/file-upload}}
Transcript
In Episode 51, we created a drag-and-drop file uploader. We got the functionality down, but it’s a bit ugly, and it’s not really intuitive how to use it. We’re going to to fix that, and along the way we’ll learn a bit more about browser events, especially dragEnter
and dragLeave
.
So we want some sort of acknowledgement that we’re dragging over the dropzone, that is aside from the disappearance of the green plus icon. We’ll create an isDragging
attribute and we’ll set it to true at first so we can see what we’re doing, and then we’ll have it as a className
binding. In our css, we’ll set the isDragging
class to change the color and the border. So that’s what it will look like when we’re dragging something over the dropzone.
To make this happen, we’ll turn off the isDragging
property as default, and then have it turned on or off when you’re leaving the dropzone. We’ll do this using the dragEnter
and dragLeave
events. And we’ll also make sure to turn off isDragging
when the drop event fires. This is a pretty cool effect, but we’re not done. We’re going to make another improvement and see how it interferes with what we just did.
The next thing to tackle is image centering. We want the image preview to be in the center of the drop field. Let’s wrap the image in the component and add in some css to make it centered. There we go. It’s centered and when we drag it in, it lights up. But when we drag it over the image, the component stops highlighting. Even worse, exiting the picture doesn’t re-highlight the component.
To diagnose the problem, we’ll put a console.log
on the dragEnter
and dragLeave
events. So then we can see that when we enter the picture, a dragEnter
and dragLeave
are both fired and both caught on our component. But the dragEnter
is usually fired before the dragLeave
, so the isDragging
attribute gets set to true again, then immediately to false. Oh-oh.
Our solution is an integer called dragCounter
. It starts at 0, and is incremented by 1 when entering and decremented by 1 when leaving. Dropping sets it to 0 again. If it’s above 0, then isDragging
is true, and the component is highlighted.
So that’s how to give good feedback for our drag-and-drop with dragEnter
and dragLeave
. Even with the complication of an internal element, Ember made things easy. So good luck out there this week, and keep on being awesome.