There are some options that can be used to customise the Row Drag experience, so it has a better integration with your application.
Entire Row Dragging Copy Link
When using row dragging it is also possible to reorder rows by clicking and dragging anywhere on the row without the need for a drag handle by enabling the rowDragEntireRow grid option.
import {
ClientSideRowModelModule,
GridApi,
GridOptions,
ModuleRegistry,
NumberFilterModule,
RowDragModule,
RowSelectionModule,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
NumberFilterModule,
RowDragModule,
RowSelectionModule,
ClientSideRowModelModule,
]);
let gridApi: GridApi<IOlympicData>;
const gridOptions: GridOptions<IOlympicData> = {
columnDefs: [
{ field: "athlete" },
{ field: "country" },
{ field: "year", width: 100 },
{ field: "date" },
{ field: "sport" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
],
defaultColDef: {
width: 170,
filter: true,
},
rowDragManaged: true,
rowDragEntireRow: true,
rowDragMultiRow: true,
rowSelection: { mode: "multiRow" },
};
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((response) => response.json())
.then((data: IOlympicData[]) => gridApi!.setGridOption("rowData", data));
<div id="myGrid" style="height: 100%"></div>
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} The example above demonstrates entire row dragging with Multi-Row Dragging. Note the following:
- Reordering rows by clicking and dragging anywhere on a row is possible as
rowDragEntireRowis enabled. - Multiple rows can be selected and dragged as
rowDragMultiRowis also enabled withrowSelection.mode = 'multiRow'. - Row Drag Managed is being used, but it is not a requirement for Entire Row Dragging.
To enable entire row dragging, set the rowDragEntireRow property to true in the gridOptions as shown below:
const gridOptions = {
columnDefs: [
{ field: 'country' },
{ field: 'year' },
{ field: 'sport' },
{ field: 'total' }
],
// allows rows to be dragged without the need for drag handles
rowDragEntireRow: true,
// other grid options ...
}Cell Selection is not supported when rowDragEntireRow is enabled.
Custom Row Drag Text Copy Link
When a row drag starts, a "floating" DOM element is created to indicate which row is being dragged. By default, this DOM element will contain the same value as the cell that started the row drag. It's possible to override that text by using the gridOptions.rowDragText callback.
import {
ClientSideRowModelModule,
ColDef,
GridApi,
GridOptions,
IRowDragItem,
ModuleRegistry,
NumberFilterModule,
RowDragModule,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
NumberFilterModule,
RowDragModule,
ClientSideRowModelModule,
]);
const rowDragText = function (params: IRowDragItem) {
// keep double equals here because data can be a string or number
if (params.rowNode!.data.year == "2012") {
return params.defaultTextValue + " (London Olympics)";
}
return params.defaultTextValue;
};
const columnDefs: ColDef[] = [
{ field: "athlete", rowDrag: true },
{ field: "country" },
{ field: "year", width: 100 },
{ field: "date" },
{ field: "sport" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
];
let gridApi: GridApi<IOlympicData>;
const gridOptions: GridOptions<IOlympicData> = {
defaultColDef: {
width: 170,
filter: true,
},
rowDragManaged: true,
columnDefs: columnDefs,
rowDragText: rowDragText,
};
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((response) => response.json())
.then((data: IOlympicData[]) => gridApi!.setGridOption("rowData", data));
<div id="myGrid" style="height: 100%"></div>
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} The example above shows dragging with custom text. The following can be noted:
- When you drag a row of the year 2012, the
rowDragTextcallback will add (London Olympics) to the floating drag element.
To enable custom row drag text, set the rowDragText callback in the gridOptions as shown below:
const gridOptions = {
columnDefs: [
{
field: 'athlete',
rowDrag: true
}, {
field: 'country'
}
],
rowDragText: (params, dragItemCount) => {
return (
dragItemCount > 1
? (dragItemCount + ' items')
: params.defaultTextValue + ' is'
) + ' being dragged...';
},
// other grid options ...
}A callback that should return a string to be displayed by the rowDragComp while dragging a row.
If this callback is not set, the current cell value will be used.
If the rowDragText callback is set in the ColDef it will take precedence over this, except when
rowDragEntireRow=true. |
Custom Row Drag Text with Multiple Draggers Copy Link
If the grid has more than one column set with rowDrag=true, the rowDragText callback can be set in the colDef.
import {
ClientSideRowModelModule,
ColDef,
GridApi,
GridOptions,
IRowDragItem,
ModuleRegistry,
NumberFilterModule,
RowDragModule,
RowSelectionModule,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
NumberFilterModule,
RowDragModule,
RowSelectionModule,
ClientSideRowModelModule,
]);
const athleteRowDragTextCallback = function (
params: IRowDragItem,
dragItemCount: number,
) {
// keep double equals here because data can be a string or number
return `${dragItemCount} athlete(s) selected`;
};
const rowDragTextCallback = function (params: IRowDragItem) {
// keep double equals here because data can be a string or number
if (params.rowNode!.data.year == "2012") {
return params.defaultTextValue + " (London Olympics)";
}
return params.defaultTextValue;
};
const columnDefs: ColDef[] = [
{
field: "athlete",
rowDrag: true,
rowDragText: athleteRowDragTextCallback,
},
{ field: "country", rowDrag: true },
{ field: "year", width: 100 },
{ field: "date" },
{ field: "sport" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
];
let gridApi: GridApi<IOlympicData>;
const gridOptions: GridOptions<IOlympicData> = {
defaultColDef: {
width: 170,
filter: true,
},
rowDragManaged: true,
columnDefs,
rowDragText: rowDragTextCallback,
rowDragMultiRow: true,
rowSelection: { mode: "multiRow" },
};
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((response) => response.json())
.then((data: IOlympicData[]) => gridApi!.setGridOption("rowData", data));
<div id="myGrid" style="height: 100%"></div>
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} The example above shows dragging with custom text and multiple column draggers. The following can be noted:
When you drag a row with a year of 2012 by the country row dragger, the
rowDragTextcallback will add (London Olympics) to the floating drag element.When you drag the row by the athlete row dragger, the
rowDragTextcallback in thegridOptionswill be overridden by the one in thecolDefand will display the number of athletes selected.
To enable custom row drag text per column dragger, set the rowDragText callback in the colDef as shown below:
const gridOptions = {
columnDefs: [
{
field: 'athlete',
rowDrag: true,
rowDragText: (params, dragItemCount) => {
const suffix = dragItemCount == 1 ? 'athlete' : 'athletes';
return `Dragging ${dragItemCount} ${suffix}`;
}
}, {
field: 'country',
rowDrag: true,
}
],
rowDragText: (params, dragItemCount) => {
return (
dragItemCount > 1
? (dragItemCount + ' items')
: params.defaultTextValue + ' is'
) + ' being dragged...';
},
// other grid options ...
} Row Dragger inside Custom Cell Renderers Copy Link
Due to the complexity of some applications, it could be handy to render the Row Drag Component inside of a Custom Cell Renderer. This can be achieved by using the registerRowDragger method in the ICellRendererParams.
import {
CellStyleModule,
ClientSideRowModelModule,
ColDef,
GridApi,
GridOptions,
ModuleRegistry,
NumberFilterModule,
RowDragModule,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { CustomCellRenderer } from "./customCellRenderer";
import { IOlympicData } from "./interfaces";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
NumberFilterModule,
RowDragModule,
CellStyleModule,
ClientSideRowModelModule,
]);
const columnDefs: ColDef[] = [
{
field: "athlete",
cellClass: "custom-athlete-cell",
cellRenderer: CustomCellRenderer,
},
{ field: "country" },
{ field: "year", width: 100 },
{ field: "date" },
{ field: "sport" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
];
let gridApi: GridApi<IOlympicData>;
const gridOptions: GridOptions<IOlympicData> = {
defaultColDef: {
width: 170,
filter: true,
},
rowDragManaged: true,
columnDefs: columnDefs,
};
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((response) => response.json())
.then((data: IOlympicData[]) => gridApi!.setGridOption("rowData", data));
.ag-ltr .ag-cell.custom-athlete-cell.ag-cell-focus:not(.ag-cell-range-selected):focus-within {
border: 1px solid #ff7b7b;
}
.ag-cell.custom-athlete-cell {
padding-left: 0;
padding-right: 0;
}
.ag-cell.custom-athlete-cell > div {
height: 100%;
}
.my-custom-cell-renderer {
display: flex;
font-size: 0.7rem;
background-color: #4180d6;
color: white;
padding: 0.25rem;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
height: 100%;
}
.my-custom-cell-renderer > * {
line-height: normal;
}
.my-custom-cell-renderer i {
visibility: hidden;
cursor: move;
color: orange;
}
.my-custom-cell-renderer:hover i {
visibility: visible;
}
.my-custom-cell-renderer .athlete-info {
display: flex;
flex-direction: column;
width: 85px;
max-width: 85px;
}
.my-custom-cell-renderer .athlete-info > span {
overflow: hidden;
text-overflow: ellipsis;
}
import type { ICellRendererComp, ICellRendererParams } from 'ag-grid-community';
export class CustomCellRenderer implements ICellRendererComp {
eGui: any;
init(params: ICellRendererParams) {
this.eGui = document.createElement('div');
this.eGui.classList.add('my-custom-cell-renderer');
this.eGui.innerHTML =
/* html */
`<div class="athlete-info">
<span>${params.data.athlete}</span>
<span>${params.data.country}</span>
</div>
<span>${params.data.year}</span>`;
// creates the row dragger element
const rowDragger = document.createElement('i');
rowDragger.classList.add('fas', 'fa-arrows-alt-v');
this.eGui.appendChild(rowDragger);
// registers as a row dragger
params.registerRowDragger(rowDragger);
}
getGui() {
return this.eGui;
}
refresh(params: ICellRendererParams): boolean {
return false;
}
}
<div id="myGrid" style="height: 100%"></div>
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} The example above shows a custom cell renderer using the registerRowDragger callback to render the Row Dragger inside itself.
- When you hover the cells, an arrow will appear, and this arrow can be used to drag the rows.
To register a custom row dragger inside a custom cell renderer, use the registerRowDragger method from the ICellRendererParams as shown below:
// your custom cell renderer init code
const rowDragger = document.createElement('div')
this.eGui.appendChild(rowDragger);
// register it as a row dragger
params.registerRowDragger(rowDragger);When using registerRowDragger you should not set the property rowDrag=true in the Column Definition. Doing that will cause the cell to have two row draggers.
Full Width Row Dragging Copy Link
It is possible to drag Full Width Rows by registering a Custom Row Dragger.
import {
ClientSideRowModelModule,
GridApi,
GridOptions,
ICellRendererParams,
IsFullWidthRowParams,
ModuleRegistry,
RowDragModule,
RowHeightParams,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { getData } from "./data";
import { FullWidthCellRenderer } from "./fullWidthCellRenderer";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
RowDragModule,
ClientSideRowModelModule,
]);
let gridApi: GridApi;
const gridOptions: GridOptions = {
columnDefs: [
{ field: "name", cellRenderer: countryCellRenderer },
{ field: "continent" },
{ field: "language" },
],
defaultColDef: {
flex: 1,
filter: true,
},
rowData: getData(),
rowDragManaged: true,
getRowHeight: (params: RowHeightParams) => {
// return 100px height for full width rows
if (isFullWidth(params.data)) {
return 100;
}
},
isFullWidthRow: (params: IsFullWidthRowParams) => {
return isFullWidth(params.rowNode.data);
},
// see AG Grid docs cellRenderer for details on how to build cellRenderers
fullWidthCellRenderer: FullWidthCellRenderer,
};
function countryCellRenderer(params: ICellRendererParams) {
if (!params.fullWidth) {
return params.value;
}
const flag =
'<img border="0" width="15" height="10" src="https://www.ag-grid.com/example-assets/flags/' +
params.data.code +
'.png">';
return (
'<span style="cursor: default;">' + flag + " " + params.value + "</span>"
);
}
function isFullWidth(data: any) {
// return true when country is Peru, France or Italy
return ["Peru", "France", "Italy"].indexOf(data.name) >= 0;
}
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
.full-width-panel {
/* undo the white-space setting Fresh puts in */
white-space: normal;
height: 100%;
width: 100%;
border: 2px solid grey;
border-style: ridge;
box-sizing: border-box;
padding: 5px;
background-color: #99999944;
}
.full-width-flag {
float: left;
padding: 6px;
}
.full-width-summary {
float: left;
/*margin-left: 10px;*/
margin-right: 10px;
}
.full-width-panel label {
padding-top: 3px;
display: inline-block;
font-size: 12px;
}
.full-width-center {
overflow-y: scroll;
border: 1px solid grey;
padding: 2px;
height: 100%;
box-sizing: border-box;
font-family: cursive;
background-color: #99999944;
}
.full-width-center p {
margin-top: 0px;
}
.full-width-title {
font-size: 20px;
}
export function getData(): any[] {
const rowData = [
{
// these attributes appear in the top level rows of the grid
name: 'Ireland',
continent: 'Europe',
language: 'English',
code: 'ie',
// these are used in the panel
population: 4000000,
},
// and then repeat for all the other countries
{
name: 'Spain',
continent: 'Europe',
language: 'Spanish',
code: 'es',
population: 4000000,
},
{
name: 'United Kingdom',
continent: 'Europe',
language: 'English',
code: 'gb',
population: 4000000,
},
{
name: 'France',
continent: 'Europe',
language: 'French',
code: 'fr',
population: 4000000,
},
{
name: 'Germany',
continent: 'Europe',
language: 'German',
code: 'de',
population: 4000000,
},
{
name: 'Sweden',
continent: 'Europe',
language: 'Swedish',
code: 'se',
population: 4000000,
},
{
name: 'Norway',
continent: 'Europe',
language: 'Norwegian',
code: 'no',
population: 4000000,
},
{
name: 'Italy',
continent: 'Europe',
language: 'Italian',
code: 'it',
population: 4000000,
},
{
name: 'Greece',
continent: 'Europe',
language: 'Greek',
code: 'gr',
population: 4000000,
},
{
name: 'Iceland',
continent: 'Europe',
language: 'Icelandic',
code: 'is',
population: 4000000,
},
{
name: 'Portugal',
continent: 'Europe',
language: 'Portuguese',
code: 'pt',
population: 4000000,
},
{
name: 'Malta',
continent: 'Europe',
language: 'Maltese',
code: 'mt',
population: 4000000,
},
{
name: 'Brazil',
continent: 'South America',
language: 'Portuguese',
code: 'br',
population: 4000000,
},
{
name: 'Argentina',
continent: 'South America',
language: 'Spanish',
code: 'ar',
population: 4000000,
},
{
name: 'Colombia',
continent: 'South America',
language: 'Spanish',
code: 'co',
population: 4000000,
},
{
name: 'Peru',
continent: 'South America',
language: 'Spanish',
code: 'pe',
population: 4000000,
},
{
name: 'Venezuela',
continent: 'South America',
language: 'Spanish',
code: 've',
population: 4000000,
},
{
name: 'Uruguay',
continent: 'South America',
language: 'Spanish',
code: 'uy',
population: 4000000,
},
];
return rowData;
}
import type { ICellRendererComp, ICellRendererParams } from 'ag-grid-community';
export class FullWidthCellRenderer implements ICellRendererComp {
eGui!: HTMLElement;
init(params: ICellRendererParams) {
// trick to convert string of html into dom object
const eTemp = document.createElement('div');
eTemp.innerHTML = this.getTemplate(params);
this.eGui = eTemp.firstElementChild as HTMLElement;
params.registerRowDragger(this.eGui, undefined, params.data.name, true);
this.consumeMouseWheelOnCenterText();
}
getTemplate(params: ICellRendererParams) {
// the flower row shares the same data as the parent row
const data = params.node.data;
const template =
'<div class="full-width-panel">' +
' <div class="full-width-flag">' +
' <img border="0" src="https://www.ag-grid.com/example-assets/large-flags/' +
data.code +
'.png">' +
' </div>' +
' <div class="full-width-summary">' +
' <span class="full-width-title">' +
data.name +
'</span><br/>' +
' <label><b>Population:</b> ' +
data.population +
'</label><br/>' +
' <label><b>Language:</b> ' +
data.language +
'</label><br/>' +
' </div>' +
' <div class="full-width-center">' +
latinText() +
' </div>' +
'</div>';
return template;
}
getGui() {
return this.eGui;
}
// if we don't do this, then the mouse wheel will be picked up by the main
// grid and scroll the main grid and not this component. this ensures that
// the wheel move is only picked up by the text field
consumeMouseWheelOnCenterText() {
const eFullWidthCenter = this.eGui.querySelector('.full-width-center')!;
const mouseWheelListener = function (event: any) {
event.stopPropagation();
};
// event is 'mousewheel' for IE9, Chrome, Safari, Opera
eFullWidthCenter.addEventListener('mousewheel', mouseWheelListener);
// event is 'DOMMouseScroll' Firefox
eFullWidthCenter.addEventListener('DOMMouseScroll', mouseWheelListener);
}
refresh(params: ICellRendererParams): boolean {
return false;
}
}
function latinText() {
return '<p>Sample Text in a Paragraph</p><p>Lorem ipsum dolor sit amet, his mazim necessitatibus te, mea volutpat intellegebat at. Ea nec perpetua liberavisse, et modo rebum persius pri. Velit recteque reprimique quo at. Vis ex persius oporteat, esse voluptatum moderatius te vis. Ex agam suscipit aliquando eum. Mediocrem molestiae id pri, ei cibo facilisis mel. Ne sale nonumy sea. Et vel lorem omittam vulputate. Ne prima impedit percipitur vis, erat summo an pro. Id urbanitas deterruisset cum, at legere oportere has. No saperet lobortis elaboraret qui, alii zril at vix, nulla soluta ornatus per ad. Feugiat consequuntur vis ad, te sit quodsi persequeris, labore perpetua mei ad. Ex sea affert ullamcorper disputationi, sit nisl elit elaboraret te, quodsi doctus verear ut eam. Eu vel malis nominati, per ex melius delenit incorrupte. Partem complectitur sed in. Vix dicta tincidunt ea. Id nec urbanitas voluptaria, pri no nostro disputationi. Falli graeco salutatus pri ea.</p><p>Quo ad omnesque phaedrum principes, tale urbanitas constituam et ius, pericula consequat ad est. Ius tractatos referrentur deterruisset an, odio consequuntur sed ad. Ea molestie adipiscing adversarium eos, tale veniam sea no. Mutat nullam philosophia sed ad. Pri eu dicta consulatu, te mollis quaerendum sea. Ei doming commodo euismod vis. Cu modus aliquip inermis his, eos et eirmod regione delicata, at odio definiebas vis.</p><p>Lorem ipsum dolor sit amet, his mazim necessitatibus te, mea volutpat intellegebat at. Ea nec perpetua liberavisse, et modo rebum persius pri. Velit recteque reprimique quo at. Vis ex persius oporteat, esse voluptatum moderatius te vis. Ex agam suscipit aliquando eum. Mediocrem molestiae id pri, ei cibo facilisis mel. Ne sale nonumy sea. Et vel lorem omittam vulputate. Ne prima impedit percipitur vis, erat summo an pro. Id urbanitas deterruisset cum, at legere oportere has. No saperet lobortis elaboraret qui, alii zril at vix, nulla soluta ornatus per ad. Feugiat consequuntur vis ad, te sit quodsi persequeris, labore perpetua mei ad. Ex sea affert ullamcorper disputationi, sit nisl elit elaboraret te, quodsi doctus verear ut eam. Eu vel malis nominati, per ex melius delenit incorrupte. Partem complectitur sed in. Vix dicta tincidunt ea. Id nec urbanitas voluptaria, pri no nostro disputationi. Falli graeco salutatus pri ea.</p><p>Quo ad omnesque phaedrum principes, tale urbanitas constituam et ius, pericula consequat ad est. Ius tractatos referrentur deterruisset an, odio consequuntur sed ad. Ea molestie adipiscing adversarium eos, tale veniam sea no. Mutat nullam philosophia sed ad. Pri eu dicta consulatu, te mollis quaerendum sea. Ei doming commodo euismod vis. Cu modus aliquip inermis his, eos et eirmod regione delicata, at odio definiebas vis.</p>';
}
<div id="myGrid" style="height: 100%"></div>
In the example above, only the full width rows are draggable.
Row Dragger with Custom Start Drag Pixels Copy Link
By default, the drag event only starts after the Row Drag Element has been dragged by 4px, but sometimes it might be useful to start the drag with a different drag threshold. For example, start dragging as soon as the mousedown event happens (dragged by 0px). For that reason, the registerRowDragger takes a second parameter to specify the number of pixels that will start the drag event.
import {
CellStyleModule,
ClientSideRowModelModule,
ColDef,
GridApi,
GridOptions,
ModuleRegistry,
NumberFilterModule,
RowDragCancelEvent,
RowDragEndEvent,
RowDragEnterEvent,
RowDragModule,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { CustomCellRenderer } from "./customCellRenderer";
import { IOlympicData } from "./interfaces";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
NumberFilterModule,
RowDragModule,
CellStyleModule,
ClientSideRowModelModule,
]);
const columnDefs: ColDef[] = [
{
field: "athlete",
cellClass: "custom-athlete-cell",
cellRenderer: CustomCellRenderer,
},
{ field: "country" },
{ field: "year", width: 100 },
{ field: "date" },
{ field: "sport" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
];
let gridApi: GridApi<IOlympicData>;
const gridOptions: GridOptions<IOlympicData> = {
defaultColDef: {
width: 170,
filter: true,
},
rowDragManaged: true,
columnDefs: columnDefs,
onRowDragEnter: onRowDragEnter,
onRowDragEnd: onRowDragEnd,
onRowDragCancel: onRowDragCancel,
};
function onRowDragEnter(e: RowDragEnterEvent) {
console.log("onRowDragEnter: node", e.node.id);
}
function onRowDragEnd(e: RowDragEndEvent) {
console.log("onRowDragEnd: node", e.node.id);
}
function onRowDragCancel(e: RowDragCancelEvent) {
console.log("onRowDragCancel: node", e.node.id);
}
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((response) => response.json())
.then((data: IOlympicData[]) => gridApi!.setGridOption("rowData", data));
.ag-ltr .ag-has-focus .ag-cell.custom-athlete-cell.ag-cell-focus:not(.ag-cell-range-selected) {
border: 1px solid #ff7b7b;
}
.ag-cell.custom-athlete-cell {
padding-left: 0;
padding-right: 0;
}
.ag-cell.custom-athlete-cell > div {
height: 100%;
}
.my-custom-cell-renderer {
display: flex;
font-size: 0.7rem;
background-color: #4180d6;
color: white;
padding: 0.25rem;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
height: 100%;
}
.my-custom-cell-renderer > * {
line-height: normal;
}
.my-custom-cell-renderer i {
visibility: hidden;
cursor: move;
color: orange;
}
.my-custom-cell-renderer:hover i {
visibility: visible;
}
.my-custom-cell-renderer .athlete-info {
display: flex;
flex-direction: column;
width: 85px;
max-width: 85px;
}
.my-custom-cell-renderer .athlete-info > span {
overflow: hidden;
text-overflow: ellipsis;
}
import type { ICellRendererComp, ICellRendererParams } from 'ag-grid-community';
export class CustomCellRenderer implements ICellRendererComp {
eGui: any;
init(params: ICellRendererParams) {
this.eGui = document.createElement('div');
this.eGui.classList.add('my-custom-cell-renderer');
this.eGui.innerHTML =
/* html */
`<div class="athlete-info">
<span>${params.data.athlete}</span>
<span>${params.data.country}</span>
</div>
<span>${params.data.year}</span>`;
// creates the row dragger element
const rowDragger = document.createElement('i');
rowDragger.classList.add('fas', 'fa-arrows-alt-v');
this.eGui.appendChild(rowDragger);
// registers as a row dragger
params.registerRowDragger(rowDragger, 0);
}
getGui() {
return this.eGui;
}
refresh(params: ICellRendererParams): boolean {
return false;
}
}
<div id="myGrid" style="height: 100%"></div>
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} In the example above, the drag event starts as soon as mousedown is fired.
Custom Drag and Drop Image Copy Link
The drag and drop image can be customised via the grid properties dragAndDropImageComponent and dragAndDropImageComponentParams.
Implement this interface to provide a custom drag and drop image component when dragging parts of the grid.
interface IDragAndDropImageComponent {
// Optional - props for rendering.
init?(params: IDragAndDropImageParams): void;
// Mandatory - Return the DOM element of the component, this is what the grid will display while dragging
getGui(): HTMLElement;
// Optional - Gets called once by grid after rendering is finished - if your renderer needs to do any cleanup,
// do it here
destroy?(): void;
// Mandatory - Gets called every time the grid needs to update the label of the Drag Image.
setLabel(label: string): void;
// Mandatory - Gets called every time the grid needs to update the icon of the Drag Image.
setIcon(icon: string | null, shake: boolean): void;
} IDragAndDropImageParams Copy Link
DragSource |
The grid api. |
Application context as set on gridOptions.context. |
Custom Params Copy Link
On top of the parameters provided by the grid, you can also provide your own parameters. This is useful if you want to allow configuring the component. For example, you might have parts of the grid that you want to highlight with a different colour.
colDef = {
dragAndDropImageComponent: MyDragAndDropImageComponent,
dragAndDropImageComponentParams : {
accentColour: 'SlateGray'
}
}import {
ClientSideRowModelModule,
GridApi,
GridOptions,
ModuleRegistry,
NumberFilterModule,
RowDragModule,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import { CustomDragAndDropImage } from "./customDragAndDropImage";
import { IOlympicData } from "./interfaces";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
NumberFilterModule,
RowDragModule,
ClientSideRowModelModule,
]);
let gridApi: GridApi<IOlympicData>;
const gridOptions: GridOptions<IOlympicData> = {
columnDefs: [
{ field: "athlete", rowDrag: true },
{ field: "country" },
{ field: "year", width: 100 },
{ field: "date" },
{ field: "sport" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
],
defaultColDef: {
width: 170,
filter: true,
},
rowDragManaged: true,
dragAndDropImageComponent: CustomDragAndDropImage,
dragAndDropImageComponentParams: {
accentColour: "SlateGray",
},
};
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((response) => response.json())
.then((data: IOlympicData[]) => gridApi!.setGridOption("rowData", data));
.my-custom-drag-and-drop-cover {
padding: 2rem;
color: white;
cursor: move;
display: flex;
align-items: center;
gap: 0.5rem;
border-radius: 0.5rem;
}
import type { IDragAndDropImageParams } from 'ag-grid-community';
export interface ICustomHeaderParams {
menuIcon: string;
}
export class CustomDragAndDropImage {
private params!: IDragAndDropImageParams;
private eGui!: HTMLElement;
private eIcon!: HTMLElement;
private eLabel!: HTMLElement;
init(params: IDragAndDropImageParams & { accentColour: string }) {
this.params = params;
const div = document.createElement('div');
const eLabel = (this.eLabel = document.createElement('div'));
const eIcon = (this.eIcon = document.createElement('i'));
this.eGui = div;
div.style.setProperty('background-color', params.accentColour);
div.appendChild(eIcon);
div.appendChild(eLabel);
div.classList.add('my-custom-drag-and-drop-cover');
eIcon.classList.add('fa-2x', 'fas');
}
getGui(): HTMLElement {
return this.eGui;
}
setLabel(label: string) {
this.eLabel.innerHTML = label;
}
setIcon(icon: string) {
const { eIcon, params } = this;
const { dragSource } = params;
if (!eIcon || !dragSource) {
return;
}
if (!icon) {
icon = dragSource.getDefaultIconName ? dragSource.getDefaultIconName() : 'notAllowed';
}
if (icon === 'hide' && params.api.getGridOption('suppressDragLeaveHidesColumns')) {
return;
}
eIcon.classList.toggle('fa-hand-point-left', icon === 'left');
eIcon.classList.toggle('fa-hand-point-right', icon === 'right');
eIcon.classList.toggle('fa-ban', icon === 'notAllowed');
eIcon.classList.toggle('fa-mask', icon === 'hide');
eIcon.classList.toggle('fa-thumbtack', icon === 'pinned');
eIcon.classList.toggle('fa-walking', icon === 'move');
}
}
<div id="myGrid" style="height: 100%"></div>
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
}