ExtJS drag and drop basics
There are a lot of places where a developer can use a “Drag and Drop” implementation to help the user complete a certain process in the application. Not all applications have a need for this feature. Sometimes it is not the best way to solve an interaction with your application and as it can result in a decrease of usability. However, “Drag and Drop” is a natural way to interact with your application for some workflows. Placed in a proper UX setting, it can become a very powerful and elegant way to allow users to accomplish tasks.
ExtJS offers a very clear and easy implementation of DnD for your web apps, in this post we are going to learn how “Drag and Drop” works and how we can use it in our applications.
Four steps to “Drag and Drop”.
The foundation of drag and drop operations can be boiled down to four simple operations.
- Move the mouse or pointing device to the object.
- Select the object.
- “Drag” the object to the target location.
- “Drop” the object in the desired location.
The classes involved in this operation are located in the Ext.dd namespace. The following image lists all the classes involved in the “Drag and Drop” implementation.
There are various “Drag and Drop” implementations around the framework, like ordering elements of a GridPanel, GridPanel to GridPanel, GridPanel to FormPanel and more. Using the classes above you can make any visual component of the framework draggable and droppable. To understand the basic concepts of “Drag and Drop” we are going to implement dragging dropping items between two DIV elements.
Drag and drop basic implementation.
Imagine that we have a restaurant application and we need to arrange the tables in the main room, first we need two containers or divs, one for the tables and another one for the main room. You can find the complete working example here .
Here’s the CSS & HTML required for this example.
<style> #content{ width:80%; height:400px; padding:10px; border:1px solid #000; } #tables{ float:left; width:40%; height:100%; border:1px solid #AAA; background-color:rgba(222, 222, 222, 1.0); } #mainRoom{ float:left; width:55%; height:100%; margin-left:15px; border:1px solid #AAA; background-color:rgba(222, 222, 222, 1.0); } .table{ background-color:rgba(254, 108, 98, 1.0); border-radius:2px; border:1px solid gray; width:64px; height:64px; margin:10px; color:#FFF; cursor:pointer; text-align:right; display: inline-block; } .valid-zone{ background-color:rgba(157, 229, 86, 1.0) !important; } .selected{ opacity:0.5; } </style> <div id="content"> <div id="tables"> <div class="table">1</div> <div class="table">2</div> <div class="table">3</div> <div class="table">4</div> <div class="table">5</div> <div class="table">6</div> <div class="table">7</div> <div class="table">8</div> <div class="table">9</div> <div class="table">10</div> <div class="table">11</div> <div class="table">12</div> </div> <div id="mainRoom"></div> </div>
First we need to make our tables draggable.
Ext.application({ name: 'DnD', launch: function() { var tables = Ext.get('tables').select('div'); Ext.each(tables.elements, function(el) { var dd = Ext.create('Ext.dd.DD', el, 'tablesDDGroup', { isTarget: false }); }); } }); <a title="DnD step one" href="https://fiddle.sencha.com/fiddle/6al" target="_blank" rel="noopener noreferrer">Code here</a>
In the code above we get each table div and make them draggable and assign them to a “Drag and Drop” group. Once we can move our tables around we need to set the drop target.
//we set the main room div as a drop target var mainTarget = Ext.create('Ext.dd.DDTarget', 'mainRoom', 'tablesDDGroup', { ignoreSelf: false }); <a title="DnD step 2" href="https://fiddle.sencha.com/fiddle/6am" target="_blank" rel="noopener noreferrer">Code here</a>
Now we have to override the Drag and Drop methods
var overrides = { startDrag: function(e) { console.log('startDrag'); }, onDrag: function() { console.log('onDrag'); }, onDragEnter: function(e, id) { console.log('onDragEnter'); }, onDragOver: function(e, id) { console.log('onDragOver'); }, onDragOut: function(e, id) { console.log('onDragOut'); }, onDragDrop: function(e, id) { console.log('onDragDrop'); }, onInvalidDrop: function() { console.log('onInvalidDrop'); }, endDrag: function(e, id) { console.log('endDrag'); } }; <a title="DnD step three" href="https://fiddle.sencha.com/fiddle/6an" target="_blank" rel="noopener noreferrer">Code here</a>
And we apply it to our dd object
Ext.each(tables.elements, function(el) { var dd = Ext.create('Ext.dd.DD', el, 'tablesDDGroup', { isTarget: false }); Ext.apply(dd, overrides); }); <a title="DnD step four" href="https://fiddle.sencha.com/fiddle/6ao" target="_blank" rel="noopener noreferrer">Code here</a>
No we have something like this.
It is time to implement each method we have overridden, the first methods we need to override are startDrag and onDrag so we can add some logic when the item starts to drag and it follows our mouse pointer.
startDrag: function(e) { //shortcut to access our element later if (!this.el) { this.el = Ext.get(this.getEl()); } //add a css class to add some transparency to our div this.el.addCls('selected'); //when we drop our item on an invalid place we need to return it to its initial position this.initialPosition = this.el.getXY(); }, onDrag: function(e) { //move the item where the mouse moves this.el.moveTo(e.getPageX() - 32, e.getPageY() - 32); }, <a title="DnD step five" href="https://fiddle.sencha.com/fiddle/6ap" target="_blank" rel="noopener noreferrer">Code here</a>
If we drop the item on a not valid drop zone we need to move it to its initial position.
onInvalidDrop: function() { this.el.removeCls('drop-target'); this.el.moveTo(this.initialPosition[0], this.initialPosition[1]); }, <a title="DnD step six" href="https://fiddle.sencha.com/fiddle/6aq" target="_blank" rel="noopener noreferrer">Code here</a>
When the item is dragged over a valid drop position we are going to change the color of that zone overriding the next method.
onDragEnter: function(e, id) { Ext.fly(id).addCls(‘valid-zone'); }, <a title="DnD step seven" href="https://fiddle.sencha.com/fiddle/6as" target="_blank" rel="noopener noreferrer">Code here</a>
So now when the user is not in a valid drop position, lets remove the color
onDragOut: function(e, id) { Ext.fly(id).removeCls('valid-zone'); }, <a title="DnD step eight" href="https://fiddle.sencha.com/fiddle/6at" target="_blank" rel="noopener noreferrer">Code here</a>
And finally we do the logic for dropping our item in a valid zone.
onDragDrop: function(e, id) { // change the item position to absolute this.el.dom.style.position ='absolute'; //move the item to the mouse position this.el.moveTo(e.getPageX() - 32, e.getPageY() - 32); Ext.fly(id).removeCls('valid-zone'); }, endDrag: function(e, id) { this.el.removeCls('selected'); this.el.highlight(); } <a title="DnD step nine" href="https://fiddle.sencha.com/fiddle/6au" target="_blank" rel="noopener noreferrer">Code here</a>
This is how the “Drag and Drop” implementation should look.
“Drag and Drop” using ExtJS is really easy and straightforward. The Ext.dd.DD class provides all the methods to help us monitor each phase of the “Drag and Drop” process. Implementing this patter in GridPanels, TreePanels, Forms is really straight forward too, you can se more info about this in de docs, in the Drag and Drop examples section.
Jay Garcia
Related Posts
-
Ext JS to React: Drag and Drop
This is part of the Ext JS to React blog series. You can review the…
-
Ext JS to React: Migration to Open Source
Worried about Migrating from Ext JS? Modus has the Answers Idera’s acquisition of Sencha has…