Row Dragging to an External DropZone is concerned with moving rows from the grid to different components within the same
application. When using row drag with an External DropZone, the data is moved or copied around using the grid events,
this is in contrast to standard Drag and Drop which uses browser events.
The Row Drag to an External DropZone uses the grid’s internal Managed Row Dragging system combined with row selection to
create a seamless data drag and drop experience.
The Grid API provide the following functions to add and remove an External DropZone to a Grid:
addRowDropZone
(Function) Adds a drop zone outside the grid where rows can be dropped.
removeRowDropZone
(Function) Removes an external DropZone added byaddRowDropZone
.
If you read the Managed Dragging section of the
Row Dragging documentation you probably noticed that when you sort
, filter
and rowGroup
the Grid, the managed Row
Dragging stops working. The only exception to this rule is when you register external DropZones using addRowDropZone
.
In this case, you will be able to drag from one container to another, but will not be able to drag the rows within the
grid.
Note that adding external DropZone uses the Grid API, this API can be used in JavaScript functions
through Clientside Callbacks.
Moreover, to make the Drag and Drop available at initialisation of the app, it is possible to use the Grid’s id
as
Input for the clientside callback, which will be triggered at the Grid initialisation. But to be able to use the Grid
API, the Grid must be fully initialized. To await
its initialisation, it is possible to use the async function
dash_ag_grid.getApiAsync(gridId)
.
The async grid API
dash_ag_grid.getApiAsync(gridId)
is available
in <code>dash‑ag‑grid>=2.3.0<code>
To allow dragging from the grid onto an outside element, or a different grid, call the addRowDropZone
from the grid
API. This will result in making the passed element or grid a valid target when moving rows around. If you later wish to
remove that DropZone use the removeRowDropZone
method from the grid API.
To customize the behavior of the External DropZone, addRowDropZone
takes the following functions as parameters:
// Get the Grid API
const gridAPI = await dash_ag_grid.getApiAsync(gridId)
// Define the Drop Zone
const targetContainer = document.querySelector('.target-container');
const dropZoneParams = {
// Function that returns the DropZone HTMLElement.
getContainer: () => targetContainer,
// Function that will be executed when the rowDrag enters the target.
onDragEnter: params => {
console.log('DropZone entered')
},
// Function that will be executed when the rowDrag leaves the target
onDragLeave: params => {
console.log('DropZone left')
},
// Function that will be executed when the rowDrag is dragged inside the target.
// Note: this gets called multiple times.
onDragging: params => {
console.log('Dragging inside the DropZone')
},
// Function that will be executed when the rowDrag drops rows within the target.
onDragStop: params => {
// here we create an element for the target container
const element = createElement(params.node.data);
targetContainer.appendChild(element);
}
}
// Register the Drop Zone
gridAPI.addRowDropZone(dropZoneParams);
// Deregister the Drop Zone when it is no longer required
gridAPI.removeRowDropZone(dropZoneParams);
In the example below, the following can be noted:
View the CSS classes used for this example
These CSS classes must be added to any *.css
file in the assets folder.
See Loading CSS files for more information.
.grid-green-row, .dragged-tile.tile-green {
background-color: #66c2a5 !important;
}
.grid-red-row, .dragged-tile.tile-red {
background-color: #e78ac3 !important;
}
.grid-blue-row, .dragged-tile.tile-blue {
background-color: #119dff !important;
}
.tile-container-header {
border: 1px solid;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
}
.tile-container {
background-color: lightgray;
height: 350px;
overflow: auto;
display: flex;
align-items: flex-start;
align-content: flex-start;
flex-wrap: wrap;
}
.dragged-tile {
width: calc(25% - 10px);
margin: 5px;
padding: 10px;
border-radius: 5px;
color: white;
}
View the Clientside Callbacks used for this example
These Clientside Callbacks must be added to any *.js
file in the assets folder.
See Clientside Callbacks for more information.
window.dash_clientside = window.dash_clientside || {};
window.dash_clientside.addDropZone = {
dropZoneDiv: async function (gridId) {
const gridAPI = await dash_ag_grid.getApiAsync(gridId)
const tileContainer = document.querySelector('.tile-container');
const dropZoneParams = {
getContainer: () => {
return tileContainer;
},
onDragStop: (params) => {
Object.values(params.nodes).forEach(
function (node) {
let el = document.createElement('div');
el.classList.add('dragged-tile');
el.classList.add(`tile-${node.data.color.toLowerCase()}`);
el.innerHTML = '<b>ID: ' + node.data.id +
'<b><br>Value1: ' + node.data.value1 +
'<br>Value2: ' + node.data.value2
tileContainer.appendChild(el);
}
);
},
};
gridAPI.addRowDropZone(dropZoneParams);
return window.dash_clientside.no_update
},
}
It is possible to use a generic DropZone to Drag and Drop rows from one grid to another. However, this approach will
treat the target grid as a generic HTML Element and adding the rows should be handled by the onDragStop
function.
The Grid API provide the getRowDropZoneParams
function that can be used with the Target Grid that can then be provided
to the addRowDropZone
function of the Source Grid, allowing rows to be dragged from the Source Grid and dropped at a
specific index on the Target Grid.
The Drag and Drop behavior can be customized by providing any of the
functions onDragEnter
, onDragLeave
, onDragging
, onDragStop
to the getRowDropZoneParams
function.
See Grid to Grid Complex Example
getRowDropZoneParams
(Function) Returns the RowDropZoneParams to be used by another grid’saddRowDropZone
method.
The example below uses the default getRowDropZoneParams
, the following can be noted:
View the CSS classes used for this example
These CSS classes must be added to any *.css
file in the assets folder.
See Loading CSS files for more
information.
.grid-green-row {
background-color: #66c2a5 !important;
}
.grid-blue-row {
background-color: #119dff !important;
}
.row-dragging-grid-to-grid-container {
display: flex;
align-items: center;
column-gap: 20px;
}
View the Clientside Callbacks used for this example
These Clientside Callbacks must be added to any *.js
file in the assets folder.
See Clientside Callbacks for more information.
window.dash_clientside = window.dash_clientside || {};
window.dash_clientside.addDropZone = {
dropZoneGrid2GridSimple: async function (gridIdLeft, gridIdRight) {
// Get the grids APIs
const gridLeftAPI = await dash_ag_grid.getApiAsync(gridIdLeft);
const gridRightAPI = await dash_ag_grid.getApiAsync(gridIdRight);
// Get the dropzones parameters from each grid
const gridLeftDropZone = gridLeftAPI.getRowDropZoneParams();
const gridRightDropZone = gridRightAPI.getRowDropZoneParams();
// Add RIGHT grid as dropzone of LEFT grid
gridLeftAPI.addRowDropZone(gridRightDropZone);
// Add LEFT grid as dropzone of RIGHT grid
gridRightAPI.addRowDropZone(gridLeftDropZone);
return window.dash_clientside.no_update
},
}
This example shows a more complex use case, using a customized Drag and Drop between Grids and a Bin as a DropZone to
remove the dropped rows. The following can be noted:
onDragEnter
, onDragLeave
and onDragStop
to create an animation of the Bin.View the CSS classes used for this example
These CSS classes must be added to any *.css
file in the assets folder.
See Loading CSS files for more
information.
.grid-green-row {
background-color: #66c2a5 !important;
}
.grid-blue-row {
background-color: #119dff !important;
}
.row-dragging-grid-to-grid-container {
display: flex;
align-items: center;
column-gap: 20px;
}
#div-row-dragging-grid2grid-complex-bin {
transition: transform 500ms;
}
View the Clientside Callbacks used for this example
These Clientside Callbacks must be added to any *.js
file in the assets folder.
See Clientside Callbacks for more information.
window.dash_clientside = window.dash_clientside || {};
window.dash_clientside.addDropZone = {
dropZoneGrid2GridComplex: async function (dropOption, gridIdLeft, gridIdRight) {
// Get the grids APIs
const gridLeftAPI = await dash_ag_grid.getApiAsync(gridIdLeft);
const gridRightAPI = await dash_ag_grid.getApiAsync(gridIdRight);
const addBinDropZone = sourceGridAPI => {
const binContainer = document.querySelector('#div-row-dragging-grid2grid-complex-bin');
const binDropZoneParams = {
getContainer: () => binContainer,
onDragEnter: params => {
binContainer.style.color = '#e78ac3';
binContainer.style.transform = 'scale(1.5)';
},
onDragLeave: params => {
binContainer.style.color = null;
binContainer.style.transform = 'scale(1)';
},
onDragStop: params => {
binContainer.style.color = null;
binContainer.style.transform = 'scale(1)';
// Remove dragged rows from the Source Grid
sourceGridAPI.applyTransaction({
remove: params.nodes.map(node => node.data)
});
},
}
sourceGridAPI.addRowDropZone(binDropZoneParams);
};
addBinDropZone(gridLeftAPI)
addBinDropZone(gridRightAPI)
const addGridDropZone = (sourceGridAPI, targetGridAPI) => {
const gridDropZoneParams = {
onDragStop: params => {
if (dropOption === 'move') {
// Remove dragged rows from the Source Grid
sourceGridAPI.applyTransaction({
remove: params.nodes.map(node => node.data)
});
} else if (dropOption === 'deselect') {
// Only deselect all rows
sourceGridAPI.deselectAll();
}
},
}
const gridDropZone = targetGridAPI.getRowDropZoneParams(gridDropZoneParams);
// Remove existing gridDropZone before adding the updated one depending on the dropOption
sourceGridAPI.removeRowDropZone(gridDropZone);
sourceGridAPI.addRowDropZone(gridDropZone);
};
addGridDropZone(gridLeftAPI, gridRightAPI)
addGridDropZone(gridRightAPI, gridLeftAPI)
return window.dash_clientside.no_update
},
}