PDA

View Full Version : [Solved]GridPanel cells as DropTargets



alamandrax
23 Nov 2007, 11:12 PM
I've been trying to make my GridPanel cells into DropTargets, but I don't seem to be doing it right. I'm trying to build a calendar UI from scratch (more of a learning exercise really - but that's not the point) using Ext-2.0-rc1 and have events represented by Panel objects and would like to be able to drop these event panels into specific locations on my GridPanel which represents a "Day" view.

gridDrag.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<!-- Ext Libs -->
<link rel="shortcut icon" href="http://www.jackslocum.com/favicon.ico"/>
<link rel="stylesheet" type="text/css" href="../resources/css/ext-all.css" media="screen"/>
<script type="text/javascript" src="../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext-all-debug.js"></script>
<!-- End Libs -->
<script type="text/javascript" src="gridDrag.js"></script>
</head>
<body>
<div id="grid-div"></div>
</body>
</html>

gridDrag.js:

var calendarDatesArray = new Array();

for(var i = 0; i < 96; i++) {
calendarDatesArray[i] = new Array();
calendarDatesArray[i][0] = i * 15;
calendarDatesArray[i][1] = '-';
}

function renderTime(val) {
var returnString = '';
var hours = Math.floor(val / 60);
hours < 10 ? returnString += '0' + hours : returnString += hours;
var minutes = val % 60;
minutes == 0 ? returnString += ':00' : returnString += ':'+ minutes;
return returnString;
}

var store = new Ext.data.SimpleStore({
fields: [
{name: 'time', type: 'float'},
{name: 'monday', type: 'string'}
]
});

store.loadData(calendarDatesArray);

var colModel = new Ext.grid.ColumnModel([
{id:'time', header:"Time", width:40, sortable: false, fixed: true, renderer: renderTime, dataIndex:'time'},
{id:'monday', header:"Monday", width:120, fixed: true, dataIndex:'monday'}
]);

var centerPanel = new Ext.grid.GridPanel({
id: 'calendar-grid',
store: store,
colModel: colModel,
sm: new Ext.grid.CellSelectionModel({
singleSelect: false,
listeners: {
cellselect: function(sm, row, column) {
// Do something when the cell is selected.
}
}
}),
autoExpandColumn: 'monday',
stripeRows: false,
title: 'Weekly Calendar',
width: '500'
});

var myNewPanel = new Ext.Panel({
height: '300',
width: '100',
name: 'myPanel',
id: 'myPanel',
frame: true,
layout: 'absolute',
shadow: false,
floating: true,
title: 'hello'
});

centerPanel.add(myNewPanel);
myNewPanel.setPosition(10, 10);

Ext.onReady(function(){
centerPanel.render('grid-div');

var myDDPanel = Ext.get('myPanel');
myDDPanel.dd = new Ext.dd.DragSource(myDDPanel, {
isTarget: true,
centerFrame: false
});

var myGridsColumnModel = Ext.getCmp('calendar-grid').getColumnModel();
myGridsColumnModel.dd = new Ext.dd.DropTarget(myGridsColumnModel, {
isTarget: true
});

});

I've tried setting the SelectionModel as a DropTarget, but I'm basically groping in the dark here. Would appreciate some help.

So to summarize: What would I need to do here to make the cells act as DropTargets for the floating panel?

SeaSharp
24 Nov 2007, 12:41 AM
I have got treenode to gridrow drag and drop working. Your problems, I suspect, relate to using "models" as a drop target. Are the selection and column models part of the rendered view of a grid?

My solution to drag and drop was to track the mouse over grid event and maintain a variable that notes the current row under the mouse. Secondly in the mouse over event I select the row under the mouse, (this is nice because it gives a visual clue about the drop target).

The main piece of coding to enable grid D&D is:


enableDrop: function( grid, ddGroup ){
var ddrow = new Ext.dd.DropTarget( grid.getEl(),{
ddGroup: ddGroup,
notifyDrop : this.onNotifyDrop.createDelegate(this)
});
},For the implementation of onNotifyDrop() search the forum for “notifyDrop” and you will find some examples.

alamandrax
24 Nov 2007, 12:45 AM
Thanks! I'll take your advice and try that. :)

Like I mentioned, "groping in the dark here". I'm relatively new to UI development, JavaScript and the ilk so, bear with me. Off to the search feature!

SeaSharp
24 Nov 2007, 12:56 AM
I'm relatively new to UI development, JavaScript and the ilk
Starting with Grid D&D? Brave man, that is called jumping in at the deep end ;)

I think there are plans to build D&D functionality into the Ext.Grid to make is as easy as Tree D&D but for the moment you have rely on DD primitives.

alamandrax
24 Nov 2007, 1:25 AM
Starting with Grid D&D? Brave man, that is called jumping in at the deep end ;)
How dare you sir! I have been called foolish and irreverent but never "brave"! Choose your weapons! Dawn tomorrow!

I think there are plans to build D&D functionality into the Ext.Grid to make is as easy as Tree D&D but for the moment you have rely on DD primitives.
I await that day with bated breath.

alamandrax
24 Nov 2007, 5:35 AM
So, I've started extending the GridPanel class:

gridDrag.js:

Ext.namespace('myNameSpace.ext');

myNameSpace.ext.DDGrid = function(config) {
config.enableDragDrop = true;
myNameSpace.ext.DDGrid.superclass.constructor.call(this, config);

//this.on({
// drop: {scope: this, function() {
//
// }}
//});
}

Ext.extend(myNameSpace.ext.DDGrid, Ext.grid.GridPanel, {

});

Ext.onReady(function(){
...

var centerPanel = new myNameSpace.ext.DDGrid({
...
});
...
});

1. Am I going about it the right way?
2. Will enabling DragDrop for a grid which has a cell selection model cause problems? I see a whole bunch of errors in my error console whenever I click on a cell.


Event thread: mousedown
Error:
name: TypeError
message: Statement on line 31112: Type mismatch (usually non-object value supplied where object required)
Backtrace:
Line 31112 of linked script file://localhost/C:/<path>/ext-2.0-rc1/ext-all-debug.js
if(!sm.isSelected(rowIndex) || e.hasModifier()){
Line 10001 of linked script file://localhost/C:/<path>/ext-2.0-rc1/ext-all-debug.js
var data = this.getDragData(e);
... Line 1629 of linked script file://localhost/C:/<path>/ext-2.0-rc1/ext-all-debug.js
fn.call(scope || el, e, t, o);
Line 10 of linked script file://localhost/C:/<path>/ext-2.0-rc1/adapter/ext/ext-base.js
function(R){return typeof Ext!="undefined"?P(Ext.lib.Event.getEvent(R)):false}
...

SeaSharp
24 Nov 2007, 8:08 AM
Have you heard of Premature Generalization :)

http://blogs.msdn.com/ericgu/archive/2006/08/03/687962.aspx ( see sin one )

Ok 3 points:

The enableDragDrop grid attribute seems to be about enabling drag/drop of elements within a grid. I tried to use it to support re-ordering of rows but the code got messy so I have postponed that feature. My grid supports drop handling of dropped tree nodes with enableDragDrop=false

If your objective is to support dropping of external drag proxies onto your grid then you just need to call the function I provided earlier passing in a reference to an instance of your grid. Then implement the function onNotifyDrop: function( dragSource, e, data ){;;;}

Once you have got the above 2 points working and then once you have got fed up of cloning the grid drop handler code, that is the time to derive a specialized DDGrid class.

alamandrax
24 Nov 2007, 9:52 AM
Hear of the ten types of programmers (http://blogs.techrepublic.com.com/10things/?p=262) you meet in the field? Yeah. I stray dangerously close to #10 and have a lot of #6 in me. It's a failing, I know, thanks for the heads up though :"> appreciate it.


If your objective is to support dropping of external drag proxies onto your grid then you just need to call the function I provided earlier passing in a reference to an instance of your grid. Then implement the function onNotifyDrop: function( dragSource, e, data ){;;;}That's exactly what I'm trying to do. I seem to have been thrown off a little by the syntax you used in the pasted code - I see now that you could have been pasting code from within an "application model (http://extjs.com/learn/Tutorial:Application_Layout_for_Beginners)". Is that assessment correct?

Let me try your suggestions and get back to you then. Thanks again for the help :)

alamandrax
24 Nov 2007, 11:52 PM
I've added the function that SeaSharp sent me and converted my JS into the application layout

gridDrag.js:

Ext.namespace('myCalendar', 'myCalendar.ext');

myCalendar.ext.app = function() {
var gridPanel;
var centerPanel;
var panelCount = 0;

var renderTime = function (val) {
var returnString = '';
var hours = Math.floor(val / 60);
hours < 10 ? returnString += '0' + hours : returnString += hours;
var minutes = val % 60;
minutes == 0 ? returnString += ':00' : returnString += ':'+ minutes;
return returnString;
}

return {
/**
* Initialize the application
*/
init: function() {
this.addCalendar();
centerPanel.render('grid-div');
this.enableDrop(centerPanel, 'myDragPanels');
},
/**
* The method that is supposed to be called when an object is dropped
* from a DragSource onto a DropTarget
*/
onNotifyDrop: function(val, val2, val3) {
Ext.Msg.alert('Value Dropped: ', val);
return false;
},
/**
* The method that initializes the dragDrop capabilities of the GridCells. (Hopefully)
*/
enableDrop: function(grid, ddGroup){
var ddrow = new Ext.dd.DropTarget(grid.getGridEl(), {
ddGroup: ddGroup,
notifyDrop : this.onNotifyDrop.createDelegate(this)
});
},
addCalendar: function() {
var calendarDatesArray = new Array();

for(var i = 0; i < 96; i++) {
calendarDatesArray[i] = new Array();
calendarDatesArray[i][0] = i * 15;
calendarDatesArray[i][1] = '-';
}

var calendarStore = new Ext.data.SimpleStore({
fields: [
{name: 'time', type: 'float'},
{name: 'monday', type: 'string'}
]
});

calendarStore.loadData(calendarDatesArray);

var colModel = new Ext.grid.ColumnModel([
{id:'time', header:"Time", width:40, sortable: false, fixed: true, renderer: renderTime, dataIndex:'time'},
{id:'monday', header:"Monday", width:120, fixed: true, dataIndex:'monday'}
]);

centerPanel = new Ext.grid.GridPanel({
id: 'calendar-grid',
store: calendarStore,
colModel: colModel,
sm: new Ext.grid.CellSelectionModel({
singleSelect: false,
listeners: {
cellselect: function(sm, row, column) {
// Do something when the cell is selected.
}
}
}),
autoExpandColumn: 'monday',
stripeRows: false,
title: 'Weekly Calendar',
width: '500'
});
},
/**
* addPanel: This method adds a panel to the centerPanel we use to hold the
* calendar grid
*/
addPanel: function(xPosition, yPosition) {
var myNewPanel = new Ext.Panel({
height: '300',
width: '100',
name: 'myPanel_' + panelCount,
id: 'myPanel_' + panelCount,
frame: true,
layout: 'absolute',
shadow: false,
floating: true,
title: 'hello'
});

centerPanel.add(myNewPanel);
centerPanel.doLayout();
var myDDPanel = Ext.get('myPanel_' + panelCount);
myDDPanel.dd = new Ext.dd.DragSource(myDDPanel, {
ddGroup: 'myDragPanels',
isTarget: true,
centerFrame: false
});
myNewPanel.setPosition(xPosition, yPosition);
panelCount++;
}
};
}();

Ext.onReady(function() {
myCalendar.ext.app.init();
myCalendar.ext.app.addPanel(1, 1);
}, myCalendar.ext.app);

The grid renders properly and the panels are added fine (more about the drag behaviour later), but I cannot drop elements into the Grid. Right now, I think the DropTarget is set to be the entire Grid and not the individual cells of the grid. I get a whole lot of errors in my Error Console (Opera 9.5) when I drag the panel onto the grid.

Opera Error console:

Event thread: mouseup
Error:
name: TypeError
message: Statement on line 31246: Cannot convert undefined or null to Object
Backtrace:
Line 31246 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/ext-all-debug.js
return this.config[colIndex].locked === true;
Line 31010 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/ext-all-debug.js
if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
Line 10242 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/ext-all-debug.js
return n ?
Line 9930 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/ext-all-debug.js
if(target.notifyDrop(this, e, this.dragData)){
Line 8645 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/ext-all-debug.js
dc.onDragDrop(e, dropEvts[i].id);
... Line 9 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/adapter/ext/ext-base.js
function(){var D=C.apply(this||window,arguments);B.apply(A||this||window,arguments);return D}
Line 8457 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/ext-all-debug.js
this.fireEvents(e, true);
... Line 1629 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/ext-all-debug.js
fn.call(scope || el, e, t, o);
Line 10 of linked script file://localhost/C:/Users/Sankar/Downloads/Safari%20Downloads/ext-2.0-rc1/adapter/ext/ext-base.js
function(R){return typeof Ext!="undefined"?P(Ext.lib.Event.getEvent(R)):false}
...


and in firebug:

this.config[colIndex] has no properties
isLocked(false)ext-all-debug.js (line 31246)
setLocked(false, false, true)ext-all-debug.js (line 31251)
onNodeDrop(td.x-grid3-hd, DDProxy myPanel_0 el=Object dragData=Object ddGroup=myDragPanels, Object browserEvent=Event resize button=-1 type=resize, Object)ext-all-debug.js (line 31013)
notifyDrop(DDProxy myPanel_0 el=Object dragData=Object ddGroup=myDragPanels, Object browserEvent=Event resize button=-1 type=resize, Object)ext-all-debug.js (line 10243)
onDragDrop(Object browserEvent=Event resize button=-1 type=resize, "ext-gen9")ext-all-debug.js (line 9930)
fireEvents(Object browserEvent=Event resize button=-1 type=resize, true)ext-all-debug.js (line 8645)
apply()ext-base.js (line 9)
handleMouseUp(Object browserEvent=Event resize button=-1 type=resize)ext-all-debug.js (line 8457)
h(Object browserEvent=Event resize button=-1 type=resize)ext-all-debug.js (line 1629)
getViewWidth(mouseup clientX=0, clientY=0)

Is this because of the SelectionModel I'm using? I should not suppose that's why it is because I've set the entire GridPanel's GridEl() to be the dropTarget...

alamandrax
25 Nov 2007, 1:09 AM
Got it!

I seem to have fixed it somewhat:

gridDrag.js:

Ext.namespace('myCalendar', 'myCalendar.ext');

myCalendar.ext.app = function() {
var gridPanel;
var centerPanel;
var panelCount = 0;

var renderTime = function (val) {
var returnString = '';
var hours = Math.floor(val / 60);
hours < 10 ? returnString += '0' + hours : returnString += hours;
var minutes = val % 60;
minutes == 0 ? returnString += ':00' : returnString += ':'+ minutes;
return returnString;
}

return {
/**
* Initialize the application
*/
init: function() {
this.addCalendar();
centerPanel.render('grid-div');
this.enableDrop(centerPanel, 'myDragPanels');
},
/**
* The method that is supposed to be called when an object is dropped
* from a DragSource onto a DropTarget
*/
onNotifyDrop: function(val, val2, val3) {
Ext.Msg.alert('Value Dropped: ', val + ' val2 : ' + this);
return false;
},
/**
* The method that initializes the dragDrop capabilities of the GridCells. (Hopefully)
*/
enableDrop: function(grid, ddGroup){
var ddrow = new Ext.dd.DropTarget(grid.getEl(), {
ddGroup: ddGroup,
notifyDrop : this.onNotifyDrop.createDelegate(this)
});
},
addCalendar: function() {
var calendarDatesArray = new Array();

for(var i = 0; i < 96; i++) {
calendarDatesArray[i] = new Array();
calendarDatesArray[i][0] = i * 15;
calendarDatesArray[i][1] = '-';
}

var calendarStore = new Ext.data.SimpleStore({
fields: [
{name: 'time', type: 'float'},
{name: 'monday', type: 'string'}
]
});

calendarStore.loadData(calendarDatesArray);

var colModel = new Ext.grid.ColumnModel([
{id:'time', header:"Time", width:40, sortable: false, fixed: true, renderer: renderTime, dataIndex:'time'},
{id:'monday', header:"Monday", width:120, fixed: true, dataIndex:'monday'}
]);

centerPanel = new Ext.grid.GridPanel({
id: 'calendar-grid',
store: calendarStore,
colModel: colModel,
sm: new Ext.grid.CellSelectionModel({
singleSelect: false,
listeners: {
cellselect: function(sm, row, column) {
// Do something when the cell is selected.
}
}
}),
autoExpandColumn: 'monday',
stripeRows: false,
title: 'Weekly Calendar',
width: '500'
});
},
/**
* addPanel: This method adds a panel to the centerPanel we use to hold the
* calendar grid
*/
addPanel: function(xPosition, yPosition) {
var myNewPanel = new Ext.Panel({
height: '300',
width: '100',
name: 'myPanel_' + panelCount,
id: 'myPanel_' + panelCount,
frame: true,
layout: 'absolute',
shadow: false,
floating: true,
title: 'hello'
});

centerPanel.add(myNewPanel);
centerPanel.doLayout();
var myDDPanel = Ext.get('myPanel_' + panelCount);
myDDPanel.dd = new Ext.dd.DragSource(myDDPanel, {
ddGroup: 'myDragPanels',
isTarget: true,
centerFrame: false
});
myNewPanel.setPosition(xPosition, yPosition);
panelCount++;
}
};
}();

Ext.onReady(function() {
myCalendar.ext.app.init();
myCalendar.ext.app.addPanel(1, 1);
}, myCalendar.ext.app);

I changed the element which is set to be the dropTarget to the grid.getEl() object. Now I get the alert correctly when I drop the panel into the cell.

I suppose this is a start. Thanks again for the help! :D