Dragging Rows from the FlexGrid

You can use the HTML5 drag/drop API to implement row dragging from, into, or between FlexGrid controls. This simple example shows how you can drag rows from the grid into arbitrary elements. You can easily extend this to support move operations (by removing the row from the source grid when the operation is completed) or dropping into grids (by detecting the drop position and inserting new rows into the target grid).

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import * as wjGrid from '@grapecity/wijmo.grid'; import { getData } from './data'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { // // create the grid var theGrid = new wjGrid.FlexGrid('#theGrid', { itemsSource: getData() }); // // allow dragging from the grid makeDragSource(theGrid); // // allow dropping into target var theTarget = document.getElementById('theTarget'); makeDropTarget(theTarget); // // make grid rows draggable function makeDragSource(s) { // // make rows draggable s.itemFormatter = function (panel, r, c, cell) { if (panel.cellType == wjGrid.CellType.RowHeader) { cell.textContent = (r + 1).toString(); cell.draggable = true; } }; // // disable built-in row drag/drop s.hostElement.addEventListener('mousedown', function (e) { if (s.hitTest(e).cellType == wjGrid.CellType.RowHeader) { e.stopPropagation(); } ; }, true); // // handle drag start s.hostElement.addEventListener('dragstart', function (e) { var ht = s.hitTest(e); if (ht.cellType == wjGrid.CellType.RowHeader) { s.select(new wjGrid.CellRange(ht.row, 0, ht.row, s.columns.length - 1)); e.dataTransfer.effectAllowed = 'copy'; e.dataTransfer.setData('text', ht.row.toString()); } ; }, true); } // // enable drop operations on an element function makeDropTarget(s) { s.addEventListener('dragover', function (e) { var dragRow = e.dataTransfer.getData('text'); if (dragRow != null) { e.dataTransfer.dropEffect = 'copy'; e.preventDefault(); } }); s.addEventListener('drop', function (e) { var dragRow = e.dataTransfer.getData('text'); if (dragRow != null) { var item = theGrid.rows[parseInt(dragRow)].dataItem; alert('thanks for dropping row ' + JSON.stringify(item) + ' here.'); e.preventDefault(); } }); } } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Drag and Drop Events</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <p> Drag rows from the grid by the row header:</p> <div id="theGrid"></div> <p> And drop them here:</p> <div id="theTarget" style="height:100px;background-color:#e0e0e0;padding:6px;border-radius:2px;"> Drop rows here... </div> </div> </body> </html> // create some random data export function getData() { var countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','), data = []; for (var i = 0; i < countries.length; i++) { data.push({ country: countries[i], downloads: Math.round(Math.random() * 20000), sales: Math.random() * 10000, expenses: Math.random() * 5000 }); } return data; } .wj-flexgrid { max-height: 250px; margin-bottom: 12px; } body { margin-bottom: 24pt; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import { Component, enableProdMode, NgModule, ViewChild } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import * as wjcGrid from '@grapecity/wijmo.grid'; import { WjGridModule } from '@grapecity/wijmo.angular2.grid'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { data: any[]; private _theColumn: string; constructor() { this.data = this._getData(); } @ViewChild('flex') flex: wjcGrid.FlexGrid ngAfterViewInit() { this._makeDragSource(this.flex); this._makeDropTarget(document.querySelector('#theTarget')); } // make grid rows draggable private _makeDragSource(s: wjcGrid.FlexGrid) { // make rows draggable s.itemFormatter = (panel: wjcGrid.GridPanel, r: number, c: number, cell: HTMLElement) => { if (panel.cellType == wjcGrid.CellType.RowHeader) { cell.textContent = (r + 1).toString(); cell.draggable = true; } }; // disable built-in row drag/drop s.addEventListener(s.hostElement, 'mousedown', (e: MouseEvent) => { if (s.hitTest(e).cellType == wjcGrid.CellType.RowHeader) { e.stopPropagation(); }; }, true); // handle drag start s.addEventListener(s.hostElement, 'dragstart', (e: DragEvent) => { let ht = s.hitTest(e); if (ht.cellType == wjcGrid.CellType.RowHeader) { s.select(new wjcGrid.CellRange(ht.row, 0, ht.row, s.columns.length - 1)); e.dataTransfer.effectAllowed = 'copy'; e.dataTransfer.setData('text', ht.row.toString()); }; }, true); } // enable drop operations on an element private _makeDropTarget(s: HTMLElement) { s.addEventListener('dragover', (e: DragEvent) => { let dragRow = e.dataTransfer.getData('text'); if (dragRow != null) { e.dataTransfer.dropEffect = 'copy'; e.preventDefault(); } }); s.addEventListener('drop', (e: DragEvent) => { let dragRow = e.dataTransfer.getData('text'); if (dragRow != null) { let item = this.flex.rows[parseInt(dragRow)].dataItem; alert('thanks for dropping row ' + JSON.stringify(item) + ' here.'); e.preventDefault(); } }); } private _getData() { // generate some random data let countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','), data = []; for (let i = 0; i < countries.length; i++) { data.push({ country: countries[i], downloads: Math.round(Math.random() * 20000), sales: Math.random() * 10000, expenses: Math.random() * 5000 }); } return data; } } // @NgModule({ imports: [WjGridModule, BrowserModule], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { } // enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Drag and Drop Events</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Polyfills --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.min.js"></script> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.js"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html> <div class="container-fluid"> <p> Drag rows from the grid by the row header:</p> <!-- the grid --> <wj-flex-grid #flex [(itemsSource)]="data"> </wj-flex-grid> <p> And drop them here:</p> <div id="theTarget" style="height:100px;background-color:#e0e0e0;padding:6px;border-radius:2px;"> Drop rows here... </div> </div> .wj-flexgrid { max-height: 250px; margin-bottom: 12px; } body { margin-bottom: 24pt; } <template> <div class="container-fluid"> <p>Drag rows from the grid by the row header:</p> <!-- the grid --> <wj-flex-grid :itemsSource="data" :initialized="initGrid"></wj-flex-grid> <p>And drop them here:</p> <div id="theTarget" style="height:100px;background-color:#e0e0e0;padding:6px;border-radius:2px;">Drop rows here...</div> </div> </template> <script> import "@grapecity/wijmo.styles/wijmo.css"; import 'bootstrap.css'; import Vue from 'vue'; import '@grapecity/wijmo.vue2.core'; import '@grapecity/wijmo.vue2.grid'; import * as wjcGrid from '@grapecity/wijmo.grid'; import { getData } from "./data"; let App = Vue.extend({ name: "app", data: function() { return { data: getData(), flex: null }; }, methods: { initGrid: function(grid) { this.flex = grid; }, // make grid rows draggable _makeDragSource: function(s) { // make rows draggable s.itemFormatter = (panel, r, c, cell) => { if (panel.cellType == wjcGrid.CellType.RowHeader) { cell.textContent = (r + 1).toString(); cell.draggable = true; } }; // disable built-in row drag/drop s.addEventListener( s.hostElement, "mousedown", e => { if (s.hitTest(e).cellType == wjcGrid.CellType.RowHeader) { e.stopPropagation(); } }, true ); // handle drag start s.addEventListener( s.hostElement, "dragstart", e => { let ht = s.hitTest(e); if (ht.cellType == wjcGrid.CellType.RowHeader) { s.select( new wjcGrid.CellRange( ht.row, 0, ht.row, s.columns.length - 1 ) ); e.dataTransfer.effectAllowed = "copy"; e.dataTransfer.setData("text", ht.row.toString()); } }, true ); }, // enable drop operations on an element _makeDropTarget: function(s) { s.addEventListener("dragover", e => { let dragRow = e.dataTransfer.getData("text"); if (dragRow != null) { e.dataTransfer.dropEffect = "copy"; e.preventDefault(); } }); s.addEventListener("drop", e => { let dragRow = e.dataTransfer.getData("text"); if (dragRow != null) { let item = this.flex.rows[parseInt(dragRow)].dataItem; alert( "thanks for dropping row " + JSON.stringify(item) + " here." ); e.preventDefault(); } }); } }, mounted: function() { this._makeDragSource(this.flex); this._makeDropTarget(document.querySelector("#theTarget")); } }); new Vue({ render: h => h(App) }).$mount("#app"); </script> <style> .wj-flexgrid { max-height: 250px; margin-bottom: 12px; } body { margin-bottom: 24pt; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AutoComplete</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/jszip/dist/jszip.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.vue'); </script> </head> <body> <div id="app"> </div> </body> </html> export function getData() { // generate some random data let countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','), data = []; for (let i = 0; i < countries.length; i++) { data.push({ country: countries[i], downloads: Math.round(Math.random() * 20000), sales: Math.random() * 10000, expenses: Math.random() * 5000 }); } return data; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './app.css'; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; import * as wjGrid from '@grapecity/wijmo.react.grid'; import * as wjcGrid from '@grapecity/wijmo.grid'; import { getData } from "./data"; class App extends React.Component { constructor(props) { super(props); this.state = { data: getData() }; } render() { return <div className="container-fluid"> <p>Drag rows from the grid by the row header:</p> <wjGrid.FlexGrid initialized={this.initGrid.bind(this)} itemsSource={this.state.data}> </wjGrid.FlexGrid> <p>And drop them here:</p> <div id="theTarget" className="theTarget">Drop rows here...</div> </div>; } initGrid(grid) { this.flex = grid; } makeDragSource(s) { // make rows draggable s.itemFormatter = (panel, r, c, cell) => { if (panel.cellType == wjcGrid.CellType.RowHeader) { cell.textContent = (r + 1).toString(); cell.draggable = true; } }; // disable built-in row drag/drop s.addEventListener(s.hostElement, "mousedown", e => { if (s.hitTest(e).cellType == wjcGrid.CellType.RowHeader) { e.stopPropagation(); } }, true); // handle drag start s.addEventListener(s.hostElement, "dragstart", e => { let ht = s.hitTest(e); if (ht.cellType == wjcGrid.CellType.RowHeader) { s.select(new wjcGrid.CellRange(ht.row, 0, ht.row, s.columns.length - 1)); e.dataTransfer.effectAllowed = "copy"; e.dataTransfer.setData("text", ht.row.toString()); } }, true); } makeDropTarget(s) { s.addEventListener("dragover", e => { let dragRow = e.dataTransfer.getData("text"); if (dragRow != null) { e.dataTransfer.dropEffect = "copy"; e.preventDefault(); } }); s.addEventListener("drop", e => { let dragRow = e.dataTransfer.getData("text"); if (dragRow != null) { let item = this.flex.rows[parseInt(dragRow)].dataItem; alert("thanks for dropping row " + JSON.stringify(item) + " here."); e.preventDefault(); } }); } componentDidMount() { this.makeDragSource(this.flex); this.makeDropTarget(document.querySelector("#theTarget")); } } ReactDOM.render(<App />, document.getElementById('app')); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Drag and Drop Events</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html> .wj-flexgrid { max-height: 200px; margin-bottom: 12px; } body { margin-bottom: 24px; } .theTarget { height:100px; background-color:#e0e0e0; padding:6px; border-radius:2px; } export function getData() { // generate some random data let countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','), data = []; for (let i = 0; i < countries.length; i++) { data.push({ country: countries[i], downloads: Math.round(Math.random() * 20000), sales: Math.random() * 10000, expenses: Math.random() * 5000 }); } return data; }