Extjs framework provides us with two helper classes responsible for performing drag-drop operation:
- Ext.dd.DragZone
- Ext.dd.DropZone
The most important element of this class is getDragData function, which provides data for drag operation.
It is necessary for this method to return object with ddel property containing DOM element, from which draging operation was originated.
This class has two important methods. The first one is getTargetFromEvent which informs if drop operation should be performed. The other one is onNodeDrop which is responsible for actual drop operation.
Having covered the basics, let’s try to implement drag-drop operation. Let’s start from creating simple container with two tables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
Ext.define('GeneralLearning.views.DragAndDropView', { extend:'Ext.container.Container', renderTpl:Ext.create('Ext.Template', '<div id="table_container">', '<table id="leftTable" style="margin: 20px 20px">', '<tr>', '<th>a</th>', '<th>b</th>', '</tr>', '<tr>', '<td>1</td>', '<td>2</td>', '</tr>', '<tr>', '<td>4</td>', '<td>9</td>', '</tr>', '<tr>', '<td>16</td>', '<td>25</td>', '</tr>', '</table>', '<table id="rightTable" style="margin: 20px 20px">', '<tr>', '<th>a</th>', '<th>b</th>', '</tr>', '<tr>', '<td>1</td>', '<td>2</td>', '</tr>', '<tr>', '<td>4</td>', '<td>9</td>', '</tr>', '<tr>', '<td>16</td>', '<td>25</td>', '</tr>', '</table>', '</div>') }) |
In the next step we will create DragZone and DropZone.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
createDragDropZones:function () { var me = this, rightTable = me.el.select('#rightTable').first(), leftTable = me.el.select('#leftTable').first(); Ext.create('Ext.dd.DragZone', rightTable, { getDragData:function (e) { if (e.target.nodeName == 'TD') { var sourceEl = e.target; var d = sourceEl.cloneNode(true); d.id = Ext.id(); return { ddel:d, sourceEl:sourceEl, repairXY:Ext.fly(sourceEl).getXY() } } }, getRepairXY:function () { return this.dragData.repairXY; } }); Ext.create('Ext.dd.DropZone', leftTable, { getTargetFromEvent:function (e) { if (e.target.nodeName == 'TD') return e.target; }, onNodeEnter:function (target, dd, e, data) { Ext.fly(target).addCls('drop-target-hover'); }, onNodeOut:function (target, dd, e, data) { Ext.fly(target).removeCls('drop-target-hover'); }, onNodeOver:function (target, dd, e, data) { return Ext.dd.DropZone.prototype.dropAllowed; }, onNodeDrop:function (target, dd, e, data) { target.parentNode.replaceChild(dd.dragData.ddel, target) return true; } }) } |
As You cas see DragZone was created on the right table. I want to be able to drag only td elements, that is why function getDragData returns null, if drag operation was originated from other HTML element. Extjs will take care of showing approperiate animation, if drag-drop is available. I also overrode getRepairXY method, which is responsible for providing X and Y coordinates for animation, which is fired in case of invalid drop off. The code responsible for handling drop operation is a little bit more complicated. After creating a DropZone from left table, I ovverode getTargetFromEvent method, so as to drop could be performed only to td elements of table. What is more, using onNodeEnter and onNodeOut methods I changed target elements of the drop, to show user where given element will be placed. Actual drop is performed in onNodeDrop method, in my case I just replace HTML node form original one to dropped.
Here is a result:
Entire code listing looks like that:
1 2 3 4 5 6 7 |
#table_container table { border: 1px solid black;float:left;width:400px;} #table_container td, #table_container th { border: 1px solid black;} td.drop-target-hover { border-color: yellow !important; border-width: 3px !important; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
Ext.define('GeneralLearning.views.DragAndDropView', { extend:'Ext.container.Container', renderTpl:Ext.create('Ext.Template', '<div id="table_container">', '<table id="leftTable" style="margin: 20px 20px">', '<tr>', '<th>a</th>', '<th>b</th>', '</tr>', '<tr>', '<td>1</td>', '<td>2</td>', '</tr>', '<tr>', '<td>4</td>', '<td>9</td>', '</tr>', '<tr>', '<td>16</td>', '<td>25</td>', '</tr>', '</table>', '<table id="rightTable" style="margin: 20px 20px">', '<tr>', '<th>a</th>', '<th>b</th>', '</tr>', '<tr>', '<td>1</td>', '<td>2</td>', '</tr>', '<tr>', '<td>4</td>', '<td>9</td>', '</tr>', '<tr>', '<td>16</td>', '<td>25</td>', '</tr>', '</table>', '</div>'), initComponent:function () { var me = this; me.callParent(arguments); me.on('afterrender', me.createDragDropZones, me); }, createDragDropZones:function () { var me = this, rightTable = me.el.select('#rightTable').first(), leftTable = me.el.select('#leftTable').first(); Ext.create('Ext.dd.DragZone', rightTable, { getDragData:function (e) { if (e.target.nodeName == 'TD') { var sourceEl = e.target; var d = sourceEl.cloneNode(true); d.id = Ext.id(); return { ddel:d, sourceEl:sourceEl, repairXY:Ext.fly(sourceEl).getXY() } } }, getRepairXY:function () { return this.dragData.repairXY; } }); Ext.create('Ext.dd.DropZone', leftTable, { getTargetFromEvent:function (e) { if (e.target.nodeName == 'TD') return e.target; }, onNodeEnter:function (target, dd, e, data) { Ext.fly(target).addCls('drop-target-hover'); }, onNodeOut:function (target, dd, e, data) { Ext.fly(target).removeCls('drop-target-hover'); }, onNodeOver:function (target, dd, e, data) { return Ext.dd.DropZone.prototype.dropAllowed; }, onNodeDrop:function (target, dd, e, data) { target.parentNode.replaceChild(dd.dragData.ddel, target) return true; } }) } }) |
Source code for this post can be found here