Search code examples
extjsextjs4

Unable to drag ExtJS 4.0.7 tree node to panel and receive notifyDrop events


I have a simple layout consisting of a Ext.tree.Panel on the left and a Ext.panel.Panel on the right. The contents of the right-hand panel are intended to be a d3 visualization.

The tree panel is defined as:

Ext.define('MyTreeModel', {
  extend: 'Ext.data.Model',
  fields: [
    { name: 'id', type: 'string' }, 
    { name: 'text', type: 'string' },
    { name: 'ddGroup', type: 'string', defaultValue: 'myDropGroup' },
    { name: 'draggable', type: 'boolean', defaultValue: true }
  ]
});

var myStore = Ext.create('Ext.data.TreeStore', {
  model: 'myTreeModel',
  autoSync: true,
  autoLoad: true,
  proxy: {
    type: 'ajax',
    url: 'myendpoint.json',
    reader: { type: 'json' }
  }
});

Ext.define('MyTreePanel', {
  extend: 'Ext.tree.Panel',
  alias: 'widget.mytreepanel',
  enableDD: true,                // not sure if this is necessary
  ddGroup: 'myDropGroup',        //             "
  rootVisible: false,
  store: myStore
}

And the panel that should receive the drop events is defined as:

Ext.define('MyDropPanel', {
  extend: 'Ext.panel.Panel',
  items: [
    {
      xtype: 'component',
      id: 'd3Component',
      autoEl: { tag: 'div' }
    }
  ],
  ddGroup: 'myDropGroup',      // not sure if this is necessary
  enableDD: true,              //           "
  listeners: {
    render: initializeDropTarget,
    afterLayout: buildInitialD3Visualization // here's where the d3 SVG gets set up
  }
});

function initializeDropTarget(panel) {
  panel.dropTarget = Ext.dd.DropTarget.create(panel.el, {
    ddGroup: 'myDropGroup',
    notifyDrop: function(dd, e, data) {
      console.log("something dropped!");  // so far I have not seen this method fire.
    }
  });
}

I am new to ExtJS but these are the things I have tried:

  1. I tried working with the plugin treeviewdragdrop. That allowed dragging and dropping within the tree but did not make and difference on whether my panel received drop events.
  2. I tried adding the enableDD property but that doesn't actually seem to be a defined property on the ExtJS 4 Panel class. And, it doesn't seem to help so far.

I wonder if the existence of a "simple" div (where the visualization is to be displayed) is what's causing the problem?


Solution

  • For Drag and Drop operation in ExtJS you need to configurate drag source and drop target.

    Drag Source

    The easiest way how to setup tree as dragSource is by using Ext.tree.plugin.TreeViewDragDrop plugin. In config of this plugin you should set name of dragGroup. By this identificator you can bind dragSource and dropTarget together.

    var tree = Ext.create('Ext.tree.Panel', {
        title: 'Simple Tree',
        width: 400,
        height: 600,
        store: store,
        rootVisible: false,            
        viewConfig: {
            plugins: {
                ptype: 'treeviewdragdrop',
                copy: true,
                dragGroup: 'myDDGroup'
            }
        },
    });
    

    Drop Target

    Then you need to create dropTarget on your Ext.panel.Panel. For this you can use Ext.dd.DropTarget. This class implements some notify methods which you can override and use for handling drag and drop events.

    The notifyDrop method is called when dragged element is dropped on target. If this method returns true drop is considered as successful.

    Because you use as dragSource treeviewdragdrop the data parameter of every notify method also contains array of records which belongs to dragged tree nodes (data.records).

    You can define your own class which extend Ext.dd.DropTarget:

    Ext.define('myPanelDropTarget', {
        extend: 'Ext.dd.DropTarget',
    
        notifyEnter : function(source, e, data) {
            console.log('enter');
            return this.callParent(arguments);
        },                
        notifyOut : function(source, e, data) {
            console.log('out');
            return this.callParent(arguments);
        },
    
        notifyOver : function(source, e, data) {
            console.log('over');
            return this.callParent(arguments);
        },                
        notifyDrop : function(source, e, data) {
            var me = this;
            console.log('drop');
    
            var text = data.records[0].get('text');
    
            var d3ComponentEl = me.panel.down('#d3Component').getEl();
    
            d3ComponentEl.insertHtml('beforeEnd', text + '<br />');                
    
            return true;
        }                           
    });
    

    Panel configured with drop target

    Finally you can setup your panel as dropTarget. dropTarget will be created in afterrender event handler because you need to bind it to panel DOM element (and this element exists only after panel is rendered). Also you have to configure dropTarget with same ddGroup name as you use in treeviewdragdrop plugin config:

    var panel = Ext.create('Ext.panel.Panel', {
        title: 'Drop Target Panel',
        border: true,
        width: 400,
        height: 600,
        items: [
            {
              xtype: 'component',
              id: 'd3Component',
              autoEl: { tag: 'div' }
            }
        ],
        listeners: {
            'afterrender': function () {
                panel.dropZone = Ext.create('myPanelDropTarget', panel.getEl(), {
                    ddGroup: 'myDDGroup',
                    panel: panel
                });                    
            }
        }            
    });
    

    I also pass panel instance into myPanelDropTarget objet because for example I am adding dropped node's name into panel content.

    Example

    Fiddle with complete live example: https://fiddle.sencha.com/#fiddle/340