View Full Version : Data View Drag and Drop to Simulate JQ UI Draggable

24 Oct 2014, 6:42 AM
I'v ebeen building out a little drag and drop data view in ExtJS and have found some helpful code which I've made some very minor adjustments to in order to have a plugin that enables drag and drop of items within a data view:

* Plugin (ptype = 'viewsortable') that makes a view "Sortable"
* via drag/drop.
Ext.define('Utils.plugins.Sortable', {

extend: 'Ext.AbstractPlugin',

alias: 'plugin.viewsortable',

mixins: {
observable: 'Ext.util.Observable'

config: {

* the event which the plugin should listen on the view,
* at this moment the plugin initiializes it's drag and drop zones
eventName: 'render',

* the class which will be added to the dragged node, then it enters a
* valid target
highlightClass: 'view-drag-highlight'

//logger: log4javascript.getLogger('Utils.plugin.Sortable'),
logger: {
debug: function (msg) {
return null;

* initialize the plugin
* @private
init: function (view) {

this.logger.debug('sortable plugin init:', view);
this.logger.debug('using event:', this.getEventName());


* @event
* event gets fired after a drag and drop action
* was successful
* @param {Utils.plugins.Sortable} this the plugin
* @param {Ext.data.Record} draggedRecord the dragged record
* @param {Ext.data.Record} targetRecord the record on which the other has droped

this.view = view;
view.on(this.getEventName(), this.initDragDrop, this);

* initialize the drag and drop behavior on the view
* @private
initDragDrop: function () {

this.logger.debug('init drag and drop');

var me = this;
var v = this.view;

var dragZone = Ext.create('Ext.dd.DragZone', this.view.getEl(), {

// On receipt of a mousedown event, see if it is within a DataView node.
// Return a drag data object if so.
getDragData: function (e) {

// Use the DataView's own itemSelector (a mandatory property) to
// test if the mousedown is within one of the DataView's nodes.
var dragHandleEl = e.getTarget(me.dragHandle || v.itemSelector, 10);
var sourceEl = e.getTarget(v.itemSelector, 10);

// If the mousedown is within a DataView node, clone the node to produce
// a ddel element for use by the drag proxy. Also add application data
// to the returned data object.

// we have added the ability to have a clone node tpl in case you need your cloned node to look drastically different
if (dragHandleEl && sourceEl) {
d = sourceEl.cloneNode(true);
d.id = Ext.id();
return {
ddel: d,
sourceEl: sourceEl,
repairXY: Ext.fly(sourceEl).getXY(),
sourceStore: v.store,
draggedRecord: v.getRecord(sourceEl)

// Provide coordinates for the proxy to slide back to on failed drag.
// This is the original XY coordinates of the draggable element captured
// in the getDragData method.
getRepairXY: function () {
return this.dragData.repairXY;

var dropZone = Ext.create('Ext.dd.DropZone', this.view.getEl(), {

// If the mouse is over a grid row, return that node. This is
// provided as the "target" parameter in all "onNodeXXXX" node event handling functions
getTargetFromEvent: function (e) {
return e.getTarget(v.itemSelector);

// On entry into a target node, highlight that node.
onNodeEnter: function (target, dd, e, data) {

// On exit from a target node, unhighlight that node.
onNodeOut: function (target, dd, e, data) {

// While over a target node, return the default drop allowed class which
// places a "tick" icon into the drag proxy.
onNodeOver: function (target, dd, e, data) {
return Ext.dd.DropZone.prototype.dropAllowed;

// On node drop we can interrogate the target to find the underlying
// application object that is the real target of the dragged data.
// In this case, it is a Record in the GridPanel's Store.
// We can use the data set up by the DragZone's getDragData method to read
// any data we decided to attach in the DragZone's getDragData method.
onNodeDrop: function (target, dd, e, data) {
me.logger.debug('onNodeDrop target', target);
me.logger.debug('onNodeDrop data', data);

var store = v.getStore();

var index = v.indexOf(target);
me.logger.debug('onNodeDrop dropped on', index);

var r = store.getAt(index);
store.insert(index, [data.draggedRecord]);
v.fireEvent('orderchange', me );
me.fireEvent('aftersort', me, data.draggedRecord, r);

// Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +
// ' on Record id ' + r.id);
return true;

However, what I really want is for the UX to follow more in the footsteps of JQuery UI's Sortable as demonstrated here: http://jqueryui.com/sortable/

Note that the "dragged item" no longer appears in the list and a blank space appears where ever the drop zone currently is. This does not happen in ExtJS.

Anyone done this before and have some pointers?

28 Oct 2014, 3:37 PM

I've not seen that sort of functionality in a dataview, though it does exist from the framework as a ux for containers. You might check out the source of the BoxReorderer class to get some ideas: