📜 ⬆️ ⬇️

Drag & Drop between TreePanel and GridPanel in ExtJS

Problem


ExtJS is a great library with a huge number of features. At http://dev.sencha.com/deploy/dev/examples/ you can find a lot of demo source codes available for use in real projects, but, of course, this will not give an answer to all the questions.
I needed to do a mutual drag between TreePanel and GridPanel. Having found on the ExtJS forum and on the Internet in general only fragmentary information, I decided to write it myself. How I did it - under the cut.


Decision


First of all, it’s worthwhile to decide - we don’t need to drag all the ExtJS files behind us. Therefore, the HTML file that starts it all looks like this:
< html >
< head >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" >
< link rel ="stylesheet" type ="text/css" href ="files/ext-all.css" >
< script type ="text/javascript" src ="files/ext-base.js" ></ script >
<script type= "text/javascript" src= "files/ext-all.js" ></script>
<script type= "text/javascript" src= "files/grid2treedrag.js" > </ script >
< title id ="page-title" > Drag&Drop TreePanel GridPanel ExtJS </ title >
</ head >
< body >
< h3 > Drag&Drop TreePanel GridPanel ExtJS </ h3 >
</ body >
</ html >


* This source code was highlighted with Source Code Highlighter .


This is the end of HTML, and go directly to JavaScript. For testing, I propose to consider a certain "basket" of the user, in the left part (GridPanel) - products, in the right part (TreePanel) - directories with them.
First, create our grid:
var grid1 = new Ext.grid.GridPanel({
store: new Ext.data.ArrayStore({
fields: [ 'name' , 'unit' , 'price' ],
data: d
}),
columns:[
{
id: 'name_column' ,
header: "" ,
width:40,
sortable: true ,
dataIndex: 'name'
},{
id: 'unit_column' ,
header: ". ." ,
width:20,
sortable: true ,
dataIndex: 'unit'
},
{
id: 'price_column' ,
header: "" ,
width:30,
sortable: true ,
dataIndex: 'price'
}
],
sm : sm,
viewConfig:{
forceFit: true
},
id: 'grid' ,
title: '' ,
region: 'center' ,
layout: 'fit' ,
enableDragDrop: true ,
ddGroup: 'grid2tree'
});


* This source code was highlighted with Source Code Highlighter .

')
d is a simple array used in ArrayStore, you can of course fill the grid in a real application in any way you like. The most important thing in the grid description is enableDragDrop set to true, and ddGroup: 'grid2tree' is the name of our drag and drop group. For a tree, it should be the same.
Now create a tree:

var tree = new Ext.tree.TreePanel({
root:{
text: '' ,
id: 'root' ,
expanded: true ,
children:[{
text: '' ,
children:[{
text: '' ,
leaf: true ,
price: 7000,
unit: ''
}, {
text: '' ,
leaf: true ,
price: 5400,
unit: ''
}, {
text: ' ' ,
children:[{
text: '' ,
leaf: true ,
price: 7000,
unit: ''
}]
}]
},{
text: ' ' ,
children:[{
text: '' ,
leaf: true ,
price: 800,
unit: ''
}]
},{
text: ' ++' ,
leaf: true ,
price: 1200,
unit: ''
}]
},
loader: new Ext.tree.TreeLoader({
preloadChildren: true
}) ,
enableDD: true ,
ddGroup: 'grid2tree' ,
id: 'tree' ,
region: 'east' ,
title: ' ' ,
layout: 'fit' ,
width:300,
split: true ,
collapsible: true ,
autoScroll: true ,
listeners:{
beforenodedrop: function (e) {

if (Ext.isArray(e.data.selections)) {
if (e.target == this .getRootNode()) {
return false ;
}
e.cancel = false ;
e.dropNode = [];
var r;
for ( var i = 0; i < e.data.selections.length; i++) {
r = e.data.selections[i];
e.dropNode.push( this .loader.createNode({
text:r.get( 'name' ),
leaf: true ,
price:r.get( 'price' ),
unit: r.get( 'unit' )
}));
r.store.remove(r);
}
return true ;
}
}
}
});


* This source code was highlighted with Source Code Highlighter .


Strings
if (e.target == this.getRootNode()) {
return false;
}

You can comment out if you want to allow dragging objects to the root element of the grid. As you can see, it is first checked whether it is an array of selected data lines (you can select several with Shift and Ctrl) what you are given to drag and drop, then loop through the selected lines and create nodes with the necessary data. I remind you that “custom” fields of the type that the price and unit we added can then be extracted from the attributes node.
Let's fasten an additional flag, the purpose of which is to demonstrate, and to which further logic is tied, as well as a window for displaying our “basket”.
var cb = new Ext.FormPanel({
region: 'south' ,
frame: true ,
height: 40,
labelWidth: 200,
labelPad: 0,
items: [
{
xtype: 'checkbox' ,
fieldLabel: ' ' ,
listeners: {
check: function (cb, checked ) {
remove_catalogs = checked ;
}
}
}
]
});

// create and show the window
var win = new Ext.Window({
title: ' ' ,
id: 'tree2divdrag' ,
border: false ,
layout: 'border' ,
width:700,
height:400,
items:[tree, grid1, cb]
});
win.show();


* This source code was highlighted with Source Code Highlighter .


Now we will create the so-called DropTarget for our grid, that is, a place where you can drag and drop objects.
var gridTargetEl = grid1.getView().scroller.dom;
We need a container element for this. If you look at the extJS demos source or ext-all-debug.js, then for the GridView you can see the following lines:
ts.master = new Ext.Template(
'<div class="x-grid3" hidefocus="true">' ,
'<div class="x-grid3-viewport">' ,
'<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset" style="{ostyle}">{header}</div></div><div class="x-clear"></div></div>' ,
'<div class="x-grid3-scroller"><div class="x-grid3-body" style="{bstyle}">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>' ,
'</div>' ,
'<div class="x-grid3-resize-marker"> </div>' ,
'<div class="x-grid3-resize-proxy"> </div>' ,
'</div>'
);


* This source code was highlighted with Source Code Highlighter .


This means that the "body" of our grid is inside the scroller framing it. Therefore, we will gain access to the scroller property that describes this wrapper and take its DOM content.

Now, using our element, create the DropTarget itself:

var GridDropTarget = new Ext.dd.DropTarget(gridTargetEl, {
ddGroup : 'grid2tree' ,
notifyDrop : function (ddSource, e, data) {
e.cancel = false ;
var node = ddSource.dragData.node;
if ( ( (node.parentNode == null ) || (!node.isLeaf() && !remove_catalogs) ) && !node.hasChildNodes() ) {
e.cancel = true ;
return false ;
}

var r = [];
if (!node.isLeaf()) {
node.cascade( function (n) {
var x = populate(n);
if (x != -1)
r.push(x);
});
}
else
r = populate(node);
grid1.store.add(r);
if ( (node.parentNode != null ) && (remove_catalogs || !node.hasChildNodes()) ) {
node.remove();
}
else {
removeChildNodes(node);
}
return true ;
}
});


* This source code was highlighted with Source Code Highlighter .


First we do checks on whether this is the root node, or whether it is possible to delete directories, and all this should not have descendants-nodes. Otherwise, go over the list of nodes, if it is not a node, or add the current node using the procedure

var populate = function (node) {
if (!node.isLeaf()) return -1;
var r = new Ext.data.Record();
r.data.name = node.text;
r.data.price = node.attributes.price;
r.data.unit = node.attributes.unit;
return r;
}


* This source code was highlighted with Source Code Highlighter .


It does not add “folders”, but only nodes, using the isLeaf () call. Then an array of records is added to the grid storage (extJS will update it itself), and nodes start to be deleted or not deleted using the procedure

var removeChildNodes = function (node) {
node.expand();
for ( var i = node.childNodes.length - 1; i >= 0; i--) {
var currentNode = node.childNodes[i];
if (currentNode.isLeaf() || remove_catalogs)
node.removeChild(currentNode);
else
removeChildNodes(currentNode);
}
}


* This source code was highlighted with Source Code Highlighter .


Without expanding the nodes, I didn’t work to remove them - the nodes in the loop go through, but they aren’t deleted, the destroy parameter set to true didn’t help either, nor did the various removeChild, expandChild, etc. options. Therefore, I will be glad to any comments, suggestions and advice that I will hear from a much more experienced habrasoobschestva.

You can see the demo here: http://www.linky.ru/~dima4ka/extjs/ (thanks to a friend for ftp access), you can also download the source code there.

useful links


http://dev.sencha.com/deploy/dev/docs/
http://www.sencha.com/forum/

Source: https://habr.com/ru/post/111236/


All Articles