:: Forum >> Version 2 >>
This example shows how to Drag and Drop Rows in a v2.0 Grid to change the row order
I hacked away at other examples and finally have a very basic example of reordering rows in a grid using drag and drop. This works in V2.0 beta 4.
Give it a try and please post enhancements. To make it easy to save to your hard drive I have uploaded it to:
http://epixpro.com/aw/dragdroprow.txt
Save that file to your ActiveWidgets directory as a html file.
Here is the code (keeping my fingers crossed that it will post right)
<html>
<head>
<script src="runtime/lib/aw.js"></script>
<link href="runtime/styles/xp/aw.css" rel="stylesheet"></link>
</head>
<body>
This is a very simple drag and drop example to move rows. <b>Click and drag a cell to move a row to a new location</b>.
<hr>
<style>
#myGrid { width: 600px; height:350px; margin: 0px; padding: 0px}
#myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;}
#myGrid .aw-alternate-odd .aw-column-0 {background: #E0E0E0;}
#myGrid .aw-alternate-even {background: #E7E7D6;}
#myGrid .aw-alternate-odd {background: #F7F3E7;}
#myGrid .aw-rows-selected {background: #316ac5;}
#myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;}
</style>
<script>
var HeaderText = ["Number","Description"];
var CellText = [
["1","Description 1"],
["2","Description 2"],
["3","Description 3"],
["4","Description 4"],
["5","Description 5"],
["6","Description 6"],
["7","Description 7"],
["8","Description 8"],
["9","Description 9"],
["10","Description 10"],
["11","Description 11"],
["12","Description 12"],
["13","Description 13"],
["14","Description 14"],
["15","Description 15"]
];
var obj = new AW.UI.Grid;
obj.setId("myGrid"); // necessary for CSS rules
obj.setHeaderText(HeaderText);
obj.setCellText(CellText);
obj.setColumnCount(2);
obj.setRowCount(15);
// DISABLE SORTING - This simple example will not work if sorted
obj.onHeaderClicked = function(event,index){return 'disabled'};
obj.setSelectionMode("single-row");
document.write(obj);
// THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
obj.onCellMouseDown = function(event, column, row){ if (column>0) dragstart(event, column, row) };
obj.onCellMouseUp = function(event, column, row){ dragstop(column, row) };
// DRAGGING FUNCTIONS
var startrow, endrow
function dragstart(e, column, row){
startrow=row;
window.status = "Drag Start Row:"+row;
}
function dragstop(column, row){
if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=null;
stoprow=row;
window.status = window.status + " dragstop row=" + stoprow;
// NOTE: THE TIMES 1 (*1) IN ALL CODE BELOW
// IS TO MAKE SURE JAVASCRIPT TREATS THE VARS
// AS NUMBERS INSTEAD OF STRINGS
//
// THIS CODE ONLY WORKS FOR A GRID BASED ON AN ARRAY.
// IT USES THE "splice" COMMAND TO ADD AND DELETE
// ROWS DIRECTLY IN THE ARRAY.
//
// ex. splice (start position, num of rows to delete, optional data to insert)
// To delete 1 row use splice(rowindex,1)
// To add a row without deleting another use spice(rowindex,0,newdata)
// GET CONTENTS OF DRAG ROW... NOTE THIS GETS THE ENTIRE ROW
// SUCH AS ["7","Description 7"]
var startrowcontents = CellText[startrow];
if ( (stoprow*1) > (startrow*1)) {
// DRAG AND DROP IN DOWNWARD DIRECTION
CellText.splice((stoprow*1)+1,0,startrowcontents); //INSERT DRAG ROW BELOW DROP ROW
CellText.splice(startrow,1); // DELETE DRAG ROW
// DRAG AND DROP IN UPWARD DIRECTION
} else if ((stoprow*1) < (startrow*1)) {
CellText.splice((stoprow*1),0,startrowcontents); // INSERT DRAG ROW ABOVE DROP ROW
CellText.splice((startrow*1)+1,1); // DELETE DRAG ROW, NOTE IT IS PUSHED DOWN 1 BECAUSE OF THE INSERT ABOVE
// DRAG AND DROP TO SAME ROW (IGNORE)
} else {
window.status = "Don't Move ... Start and Stop Row are the same ("+startrow+","+stoprow+")";
}
// FYI... IF YOU WANTED TO HARD CODE THE DATA TO INSERT IT WOULD LOOK LIKE THIS
// CellText.splice(stoprow,0,["17","Description 17"]);
obj.refresh();
}
</script>
<hr>
I tested it using AW 2.0 beta 4 and IE and Firefox 1.0. It has several limitations
<ul>
<li>Only works on ARRAY based grid.
<li>Array is manipulated directly using splice. I wanted to use addRow and deleteRow but I couldn't figure out how to set the insert location for addRow (it was always inserting at the end of the grid).
<li>No visual feedback when dragging the row ... please someone figure out how to add that :)
<li>Sorting is not supported so it is disabled
</ul>
</body>
</html>
I hope this is a good starting point and useful for others. I found some great 1.0 examples on the forum but not much for 2.0. All you great coders out there please submit a more generic and flexible example :)
Thanks!
Rob Francis
Wednesday, February 1, 2006
Rob, nice example. This will give others a place to start from. Do I have your permission to post this to the Demo page on my site.
www.FriendsOfAW.com?
Thanks for the fine effort!
Jim Hunter
Wednesday, February 1, 2006
Hey Jim ... yes please post it over there for me!
Rob Francis
Wednesday, February 1, 2006
Jim Hunter
Wednesday, February 1, 2006
Great example!!! Before looking at this code I was always thinking that drag-and-drop is something very complex :-)
Alex (ActiveWidgets)
Wednesday, February 1, 2006
To make it working with RC1 add #myGrid {-moz-user-select: none} to the style block.
Alex (ActiveWidgets)
Wednesday, February 1, 2006
Alex ... That worked! Plus a quick run through of my other V2 code is looking good under RC1 too.
I also added a add row and delete row button to this example with the code below:
Added this Javascript
function del(){
var insertindex=obj.getCurrentRow();
CellText.splice(insertindex,1);
obj.setRowCount(obj.getRowCount()-1);
obj.refresh();
}
function add(){
var insertindex=obj.getCurrentRow();
CellText.splice((insertindex*1)+1,0,["new","new"]);
obj.setRowCount(obj.getRowCount()+1);
obj.refresh();
}
Added this HTML
<button onclick="add()">add row below current</button>
<button onclick="del()">delete current row</button>
The full updated version is at:
http://www.epixpro.com/aw/dragdroprow.txt
Rob Francis
Wednesday, February 1, 2006
Hi Rob,
Thanks , it's a Nice & very useful Sample:
I just discovered a small bug in this sample ( it happens after dragging any row in col-1 and then do a row-drag in col-0 "intend to be disabled").
It can be easy solved by doing a little change in oncellMouseDown/oncellMouseUp functions by:
// THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
obj.onCellMouseDown = function(event, column, row){
if (column>0) {dragstart(event, column, row) }
else { startrow = null }
};
obj.onCellMouseUp = function(event, column, row){
if (startrow) { dragstop(column, row) }
};
And here is (as requested) ;-) my first attempt to add a visual row-drag-effect :
It is based on a great Austin Mayberry's sample page enhancement drag-drop-columns (which I'm currently triyng to convert too )
(but in this case adapted for rows and V2.0):
/javascript.forum.3258.21/dropdown-grid-template.html
( Did not test it a lot (especially inside div/table and many other situations, so could be buggy also).
Please report any issue found:
HTH
var RowsArea = obj.getRowsTemplate();
var mouseCelldown = false;
var RowTarget;
var CellTarget;
var TopRowTG;
var rightScroll;
var bottomScroll;
/*****************/
var dragColStart = function(event) {
if(!AW.ie) { CellTarget = event.target }
else{ CellTarget = event.srcElement }
var sECId = CellTarget.id ;
if (sECId.indexOf("-box-text") > 0 ){ RowTarget = CellTarget.parentNode.parentNode }
else { RowTarget = CellTarget.parentNode }
rightScroll = obj.getScrollLeft();
bottomScroll = obj.getScrollTop();
TopRowTG = RowTarget.parentNode.firstChild;
RowTarget.width=RowTarget.offsetWidth;
RowTarget.height=RowTarget.offsetHeight;
///get column number
var arrofcolumns = CellTarget.id.split("-");
//disable row-drag visual effect on some rows (IN CURRENT SAMPLE ROW 0 IS DISABLED)
if ( arrofcolumns[2] >0 ){ mouseCelldown = true }
else {mouseCelldown = false }
}
/********************************/
var dragCol = function(event) {
if(!AW.ie) { var x = event.pageX ; var y = event.pageY ; }
else{ var x = event.screenX ; var y=event.screenY }
var DragRow = document.getElementById('DragRow');
if(DragRow) {
if(!AW.ie){
if(rightScroll==0){ DragRow.style.left = x - AW.getLeft(CellTarget) - obj.getSelectorWidth() }
else{ DragRow.style.left = x + rightScroll - AW.getLeft(CellTarget) - obj.getSelectorWidth() }
if(bottomScroll==0){ DragRow.style.top = y - AW.getTop(TopRowTG) + 3; }
else{ DragRow.style.top = y + bottomScroll - AW.getTop(TopRowTG) + 3 }
}
if( AW.ie){
DragRow.style.left = x - window.screenLeft - AW.getLeft(CellTarget) - obj.getSelectorWidth() + 8 ;
DragRow.style.top = y - window.screenTop - AW.getTop(TopRowTG) + 3 ;
}
}
else if(mouseCelldown){
var DragRow = RowTarget.cloneNode(true)
DragRow.id = "DragRow";
DragRow.style.position = "absolute";
DragRow.style.width = RowTarget.width;
DragRow.style.height = RowTarget.height;
DragRow.style.zIndex = 1000000;
DragRow.style.MozOpacity = 0.7;
DragRow.style.filter = "alpha(opacity=70)"
RowTarget.parentNode.appendChild(DragRow);
}
}
/***********************/
obj.setEvent("onmousemove", dragCol);
RowsArea.setEvent("onmousedown", dragColStart);
Carlos
Thursday, February 9, 2006
Uppps SORRY, Comented line:
//disable row-drag visual effect on some rows (IN CURRENT SAMPLE ROW 0 IS DISABLED)
Should say COLUMNS
Thursday, February 9, 2006
Hi Carlos,
Thanks for the bug fix... actually the code that disables (ignores) column zero is left over from the sample I started with. I didn't intend that have that in there but I missed it :)
I would really like to see your visual feedback enhancement but I can't get it to work. I tried adding it to my sample but I must have something wrong.
Can you post the full example.
Thanks!
Rob Francis
Thursday, February 9, 2006
I forgot to say that documnet.write(obj) must be at the bottom of all, (if not the first click on the grid does not fire the visual-e), but after that any dragging works . Could be this ???
I could not locate any other change than I commented your line :
// if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=null;
But if I un-commet it works also.
Anyway here is the complete sample :
Carlos.
<html>
<head>
<script src="../../runtime/lib/aw.js"></script>
<link href="../../runtime/styles/xp/aw.css" rel="stylesheet"></link>
</head>
<body>
This is a very simple drag and drop example to move rows. <b>Click and drag a cell to move a row to a new location</b>.
<hr>
<style>
#myGrid { width: 300px; height:150px; margin: 0px; padding: 0px}
#myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;}
#myGrid .aw-alternate-odd .aw-column-0 {background: #E0E0E0;}
#myGrid .aw-alternate-even {background: #E7E7D6;}
#myGrid .aw-alternate-odd {background: #F7F3E7;}
#myGrid .aw-rows-selected {background: #316ac5;}
#myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;}
#myGrid {-moz-user-select: none}
</style>
<script>
var HeaderText = ["Number","Description"];
var CellText = [
["1","Description 1"],
["2","Description 2"],
["3","Description 3"],
["4","Description 4"],
["5","Description 5"],
["6","Description 6"],
["7","Description 7"],
["8","Description 8"],
["9","Description 9"],
["10","Description 10"],
["11","Description 11"],
["12","Description 12"],
["13","Description 13"],
["14","Description 14"],
["15","Description 15"]
];
var obj = new AW.UI.Grid;
obj.setId("myGrid"); // necessary for CSS rules
obj.setHeaderText(HeaderText);
obj.setCellText(CellText);
obj.setColumnCount(2);
obj.setRowCount(15);
// DISABLE SORTING - This simple example will not work if sorted
obj.onHeaderClicked = function(event,index){return 'disabled'};
obj.setSelectionMode("single-row");
obj.setSelectorVisible(true);
// obj.setSelectorResizable(true);
obj.setSelectorWidth(25);
// obj.setControlSize(100, 200); // width, height
// obj.setControlPosition(327, 50); // left, top - adds 'position:absolute'
// document.write(obj);
// THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
obj.onCellMouseDown = function(event, column, row){
if (column>0) {dragstart(event, column, row) }
else { startrow = null }
};
obj.onCellMouseUp = function(event, column, row){
if (startrow) { dragstop(column, row) }
};
// DRAGGING FUNCTIONS
var startrow, endrow ;
/**********************/
function dragstart(e, column, row){
startrow=row;
window.status = "Drag Start Row:"+row;
}
function dragstop(column, row){
// if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=null;
stoprow=row;
window.status = window.status + " dragstop row=" + stoprow;
// NOTE: THE TIMES 1 (*1) IN ALL CODE BELOW
// IS TO MAKE SURE JAVASCRIPT TREATS THE VARS
// AS NUMBERS INSTEAD OF STRINGS
//
// THIS CODE ONLY WORKS FOR A GRID BASED ON AN ARRAY.
// IT USES THE "splice" COMMAND TO ADD AND DELETE
// ROWS DIRECTLY IN THE ARRAY.
//
// ex. splice (start position, num of rows to delete, optional data to insert)
// To delete 1 row use splice(rowindex,1)
// To add a row without deleting another use spice(rowindex,0,newdata)
// GET CONTENTS OF DRAG ROW... NOTE THIS GETS THE ENTIRE ROW
// SUCH AS ["7","Description 7"]
var startrowcontents = CellText[startrow];
if ( (stoprow*1) > (startrow*1)) {
// DRAG AND DROP IN DOWNWARD DIRECTION
CellText.splice((stoprow*1)+1,0,startrowcontents); //INSERT DRAG ROW BELOW DROP ROW
CellText.splice(startrow,1); // DELETE DRAG ROW
// DRAG AND DROP IN UPWARD DIRECTION
} else if ((stoprow*1) < (startrow*1)) {
CellText.splice((stoprow*1),0,startrowcontents); // INSERT DRAG ROW ABOVE DROP ROW
CellText.splice((startrow*1)+1,1); // DELETE DRAG ROW, NOTE IT IS PUSHED DOWN 1 BECAUSE OF THE INSERT ABOVE
// DRAG AND DROP TO SAME ROW (IGNORE)
} else {
window.status = "Don't Move ... Start and Stop Row are the same ("+startrow+","+stoprow+")";
}
// FYI... IF YOU WANTED TO HARD CODE THE DATA TO INSERT IT WOULD LOOK LIKE THIS
// CellText.splice(stoprow,0,["17","Description 17"]);
obj.setSelectedRows([stoprow]);
mouseCelldown = false;
obj.refresh();
}
function del(){
var insertindex=obj.getCurrentRow();
CellText.splice(insertindex,1);
obj.setRowCount(obj.getRowCount()-1);
obj.refresh();
}
function add(){
var insertindex=obj.getCurrentRow();
CellText.splice((insertindex*1)+1,0,["new","new"]);
obj.setRowCount(obj.getRowCount()+1);
obj.refresh();
}
/************************/
var RowsArea = obj.getRowsTemplate();
var mouseCelldown = false;
var RowTarget;
var CellTarget;
var TopRowTG;
var rightScroll;
var bottomScroll;
/*****************/
var dragColStart = function(event) {
if(!AW.ie) { CellTarget = event.target }
else{ CellTarget = event.srcElement }
var sECId = CellTarget.id ;
if (sECId.indexOf("-box-text") > 0 ){ RowTarget = CellTarget.parentNode.parentNode }
else { RowTarget = CellTarget.parentNode }
rightScroll = obj.getScrollLeft();
bottomScroll = obj.getScrollTop();
TopRowTG = RowTarget.parentNode.firstChild;
RowTarget.width=RowTarget.offsetWidth;
RowTarget.height=RowTarget.offsetHeight;
///get column number
var arrofcolumns = CellTarget.id.split("-");
//disable row-drag visual effect on some COLUMNS (IN CURRENT SAMPLE DRAG IN COLUMN-0 IS DISABLED)
if ( arrofcolumns[2] >0 ){ mouseCelldown = true }
else {mouseCelldown = false }
}
/********************************/
var dragCol = function(event) {
if(!AW.ie) { var x = event.pageX ; var y = event.pageY ; }
else{ var x = event.screenX ; var y=event.screenY }
var DragRow = document.getElementById('DragRow');
if(DragRow) {
if(!AW.ie){
if(rightScroll==0){ DragRow.style.left = x - AW.getLeft(CellTarget) - obj.getSelectorWidth() }
else{ DragRow.style.left = x + rightScroll - AW.getLeft(CellTarget) - obj.getSelectorWidth() }
if(bottomScroll==0){ DragRow.style.top = y - AW.getTop(TopRowTG) + 3; }
else{ DragRow.style.top = y + bottomScroll - AW.getTop(TopRowTG) + 3 }
}
if( AW.ie){
DragRow.style.left = x - window.screenLeft - AW.getLeft(CellTarget) - obj.getSelectorWidth() + 8 ;
DragRow.style.top = y - window.screenTop - AW.getTop(TopRowTG) + 3 ;
}
}
else if(mouseCelldown){
var DragRow = RowTarget.cloneNode(true)
DragRow.id = "DragRow";
DragRow.style.position = "absolute";
DragRow.style.width = RowTarget.width;
DragRow.style.height = RowTarget.height;
DragRow.style.zIndex = 1000000;
DragRow.style.MozOpacity = 0.7;
DragRow.style.filter = "alpha(opacity=70)"
RowTarget.parentNode.appendChild(DragRow);
}
}
/***********************/
obj.setEvent("onmousemove", dragCol);
RowsArea.setEvent("onmousedown", dragColStart);
document.write(obj);
</script>
<br>
<button onclick="add()">add row below current</button>
<button onclick="del()">delete current row</button>
<hr>
I tested it using AW 2.0 beta 4 and IE and Firefox 1.0. It has several limitations
<ul>
<li>Only works on ARRAY based grid.
<li>Array is manipulated directly using splice. I wanted to use addRow and deleteRow but I couldn't figure out how to set the insert location for addRow (it was always inserting at the end of the grid).
<li>No visual feedback when dragging the row ... please someone figure out how to add that :)
<li>Sorting is not supported so it is disabled
</ul>
</body>
</script>
</html>
Thursday, February 9, 2006
Outstanding Carlos! This is exactly what I was hoping for.
I've made one more enhancement but it still has bugs... if you have time please help.
The code below contains my original sample PLUS your visual feedback PLUS auto scroll. The auto scroll lets you (for example) drag row 1 all the way down to row 15. Since row 15 is not visible the grid has to scroll as you get near the bottom.
The problem is if you go past the bottom of the grid then your visual feedback disappears. I think it is a problem with RowTarget.parentNode returning null.
<html>
<head>
<script src="../../runtime/lib/aw.js"></script>
<link href="../../runtime/styles/xp/aw.css" rel="stylesheet"></link>
</head>
<body>
This is a very simple drag and drop example to move rows. <b>Click and drag a cell to move a row to a new location</b>.
<hr>
<style>
#myGrid { width: 300px; height:150px; margin: 0px; padding: 0px}
#myGrid .aw-alternate-even .aw-column-0 {background: #E0E0E0;}
#myGrid .aw-alternate-odd .aw-column-0 {background: #E0E0E0;}
#myGrid .aw-alternate-even {background: #E7E7D6;}
#myGrid .aw-alternate-odd {background: #F7F3E7;}
#myGrid .aw-rows-selected {background: #316ac5;}
#myGrid .aw-rows-selected .aw-column-1 {background: #316ac5;}
#myGrid {-moz-user-select: none}
</style>
<script>
var HeaderText = ["Number","Description"];
var CellText = [
["1","Description 1"],
["2","Description 2"],
["3","Description 3"],
["4","Description 4"],
["5","Description 5"],
["6","Description 6"],
["7","Description 7"],
["8","Description 8"],
["9","Description 9"],
["10","Description 10"],
["11","Description 11"],
["12","Description 12"],
["13","Description 13"],
["14","Description 14"],
["15","Description 15"]
];
var obj = new AW.UI.Grid;
obj.setId("myGrid"); // necessary for CSS rules
obj.setHeaderText(HeaderText);
obj.setCellText(CellText);
obj.setColumnCount(2);
obj.setRowCount(15);
// DISABLE SORTING - This simple example will not work if sorted
obj.onHeaderClicked = function(event,index){return 'disabled'};
obj.setSelectionMode("single-row");
obj.setSelectorVisible(true);
// obj.setSelectorResizable(true);
obj.setSelectorWidth(25);
// obj.setControlSize(100, 200); // width, height
// obj.setControlPosition(327, 50); // left, top - adds 'position:absolute'
// document.write(obj);
// THESE ARE CALLED TO START AND STOP THE DRAG AND DROP OF ROWS
obj.onCellMouseDown = function(event, column, row){
if (column>0) {dragstart(event, column, row) }
else { startrow = null }
};
obj.onCellMouseUp = function(event, column, row){
if (startrow) { dragstop(column, row) }
};
// DRAGGING FUNCTIONS
var startrow, endrow ;
var dragapproved=false
var offsetx, offsety, tmpx, tmpy, maxx, maxy,scrollupy, scrolldowny
/**********************/
function dragstart(e, column, row){
dragapproved=true;
startrow=row;
offsety=event.clientY;
scrollupy=obj.getHeaderHeight()+80;
scrolldowny=document.getElementById("myGrid").offsetHeight+20;
tmpy=obj.getScrollTop();
maxy=obj.getScrollHeight() - document.getElementById("myGrid").offsetHeight + 18;
// if (document.getElementById("myGrid")) document.getElementById("myGrid").onmousemove=dragdrop
window.status = "Drag Start Row:"+row;
}
function dragdrop(e){
if (dragapproved&&event.button==1){
if (event.clientY<scrollupy) {
window.status="go backwards Y: "+event.clientY;
y=obj.getScrollTop()-20;
if (y<0) y=0;
obj.setScrollTop(y);
}
if (event.clientY>scrolldowny) {
window.status="go to: "+event.clientY;
obj.setScrollTop(obj.getScrollTop()+20);
y=obj.getScrollTop()+20;
if (y>maxy)y=maxy;
obj.setScrollTop(y);
}
}&nbs