Why?
In part 1 of Merging Rails with ember-cli, I talked about techniques that I use to achieve a smooth development experience when combining a Rails API with an Ember CLI-powered front end. I wanted to build a simple app where people could vote for beer by ranking their favorites on a weighted 1 to N scale. However, I was unsure how Ember would handle a major component of the app: drag-n-drop.In this post, I will go into more detail about how I implemented HTML5 drag-n-drop functionality for updating beer rankings. I will demonstrate how simple it was to build this functionality into my existing, non-dynamic list of beers.
##VS
##BootstrappingI love to use twitter bootstrap when I am prototyping a new idea. Just run...$ bower install --save-dev ember-cli-bootstrap-sass
...then add the following to the top of your root scss stylesheet:EmberApp/app/styles/app.scss@import "bootstrap";
@import "bootstrap/theme";
##Drag-N-DropWe've all heard this request before: "I just want to be able to drag this item here and this item there and POOF, the change is made!" Clients LOVE drag-n-drop. It is a feature I have implemented a million times before, but I almost always use some JQuery library that interfaces with a custom-built API for the sole purpose of building that ONE drag-n-drop component. I was seriously scared that drag-n-drop would be really hard to build in pure Ember, but I am pleased to say that I had it up and running in no time!The first thing I did was hit the docs. I was pleased to see that EmberView supports drag and drop out of the box. This worked out perfectly, since I knew I would need two views in this component: a line item and a slot to drop each line item into. So, I created myself a line-item and an item-slot view with the necessary event dataTransfer data.I had to comb through the w3c spec a bit, but I was able to come up with some solid documentation on HTML5 drag-n-drop and the data transfer interface.EmberApp/app/views/line-item.jsimport Ember from 'ember';
export default Ember.View.extend({
attributeBindings: ['draggable'],
draggable: 'true',
templateName: 'line-item',
classNames: 'line_item',
dragStart: function(ev){
var dragData = { id: this.content.get('id') };
ev.dataTransfer.setData('application/json', JSON.stringify(dragData));
}
});
EmberApp/app/templates/line-item.hbs<span class="weight">{{weight}}</span>
<span class="name">{{beer_name}}</span>
EmberApp/app/views/item-slot.jsimport Ember from 'ember';
export default Ember.View.extend({
templateName: 'item-slot',
dragOver: function(ev){
ev.preventDefault();
},
drop: function(ev){
var data = JSON.parse(ev.dataTransfer.getData('application/json'));
this.get('controller').send('swap', data.id, this.content.get('id'));
}
});
EmberApp/app/templates/item-slot.hbs{{view 'line-item' contentBinding='this'}}
Lastly, I updated my ballot template to use these new views.EmberApp/app/templates/ballot.hbs{{#each this.model.sorted_line_items}}
<div class="row"></div>
<div class="col-xs-12">{{view 'item-slot' contentBinding='this'}}</div>
{{/each}}
<div class="row"></div>
<div class="col-xs-12 new_beer">{{#view 'new-beer' contentBinding='this'}}</div>
<input type="text" placeholder="+ ADD BEER">
{{/view}}
Then I update my controller to handle swapping of weights between two line items. It's a little dirty, but it gets the job done:EmberApp/app/controller/ballot.jsimport Ember from 'ember';
export default Ember.Controller.extend({
sortProperties: ['weight'],
actions: {
swap: function(line_item_id_1, line_item_id_2) {
var li1, li1_weight, li2, li2_weight;
li1 = this.model.get('line_items').findBy('id', line_item_id_1);
li2 = this.model.get('line_items').findBy('id', line_item_id_2);
li1_weight = li1.get('weight');
li2_weight = li2.get('weight');
li1.set('weight', li2_weight);
li2.set('weight', li1_weight);
}
}
});
That’s it, drag-n-drop now works! Yet again Ember proves itself to be an amazing framework for building incredibly dynamic single-page apps with great speed.In Part 3, I will show you how to persist these changes that you make to your backend Rails application!##Resources* Ember-CLI Rails Github Repo* HTML5 Drag and Drop* Part 1* Part 3Cover photo by OUCHcharley