Custom Editors (React)

Although the FlexGrid control provides efficient, Excel-style editing by default, you may want to customize the editing experience by using custom editors.

This is easily done by assigning an instance of an editor control to the column's editor property. This sample demonstrates this using Wijmo's InputDate, InputTime, ComboBox, AutoComplete, and InputColor, InputNumber controls.

Learn about FlexGrid | FlexGrid Documentation | FlexGrid API Reference

This example uses React.

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import ReactDOM from 'react-dom/client'; import React from 'react'; import { FlexGrid, FlexGridColumn } from '@mescius/wijmo.react.grid'; import { DataMap } from '@mescius/wijmo.grid'; import { InputDate, InputTime, ComboBox, AutoComplete, InputColor, InputNumber, InputMask, MultiSelect } from '@mescius/wijmo.input'; import './app.css'; import { data, countries, products, names } from './data'; function App() { return (<div className="container-fluid"> <FlexGrid showMarquee={true} alternatingRowStep={0} selectionMode="MultiRange" itemsSource={data}> <FlexGridColumn binding="id" header="ID" width={80} isReadOnly={true}/> <FlexGridColumn binding="date" header="Date" format="d" editor={new InputDate(document.createElement('div'))}/> <FlexGridColumn binding="time" header="Time" format="t" editor={new InputTime(document.createElement('div'), { format: 't', step: 30 })}/> <FlexGridColumn binding="country" header="Country" editor={new ComboBox(document.createElement('div'), { itemsSource: countries })}/> <FlexGridColumn binding="productId" header="Product" dataMap={new DataMap(products, 'id', 'name')} editor={new AutoComplete(document.createElement('div'), { itemsSource: products, selectedValuePath: 'id', displayMemberPath: 'name' })}/> <FlexGridColumn binding="name" header="Names" width={250} editor={new MultiSelect(document.createElement('div'), { itemsSource: names, showSelectAllCheckbox: true })}/> <FlexGridColumn binding="phone" header="Phone" editor={new InputMask(document.createElement('div'), { mask: '(000) 000-0000' })}/> <FlexGridColumn binding="color" header="Color" cellTemplate='<span class="colorbox" style="background:${text};"></span> ${text}' editor={new InputColor(document.createElement('div'))}/> <FlexGridColumn binding="amount" header="Amount" format="n2" editor={new InputNumber(document.createElement('div'), { format: 'n2', step: 10, min: 0, max: 10000 })}/> <FlexGridColumn binding="premium" header="Premium" cssClass="switch"/> </FlexGrid> </div>); } const container = document.getElementById('app'); if (container) { const root = ReactDOM.createRoot(container); root.render(<App />); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo Wijmo FlexGrid Custom Editors</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.40/system.src.js" integrity="sha512-G6mEj6h18+m3MvzdviSDfPle/TfH0//cXcB33AKlNR/Rha0yQsKefDZKRTkIZos97HEGq2JMV1RT5ybMoQ3WsQ==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html>
.wj-flexgrid { height: 300px; margin-bottom: 12px; } .wj-flexgrid .wj-cell { padding: 6px 8px; } .colorbox { display: inline-block; width: 12px; height: 1.5em; margin: 0 3px 0 -3px; border: 1px solid black; vertical-align: bottom; } /* switch-style checkbox */ .wj-cell.switch input[type=checkbox] { opacity: 0; width: 100%; } .wj-cell.switch label { width: 3em; position: relative; } .wj-cell.switch input[type=checkbox]+span { pointer-events: none; background: rgba(0, 0, 0, 0.4); } .wj-cell.switch input[type=checkbox]:checked+span { background: #0085c7; /* rgb(27, 255, 27) */ } .wj-cell.switch:hover input[type=checkbox]+span:after { box-shadow: 0 3px 3px rgba(0, 0, 0, 0.4); transition: all 0.3s; } .wj-cell.switch input[type=checkbox]+span:before { content: ''; position: absolute; display: block; left: 0; top: .45em; width: 2.5em; height: .75em; border-radius: 1em; background: rgba(0, 0, 0, .4); opacity: .25; } .wj-cell.switch input[type=checkbox]:checked+span:before { background: inherit; } .wj-cell.switch input[type=checkbox]+span:after { content: ''; position: absolute; left: 0; top: 0.13em; width: 1.3em; height: 1.3em; background: white; border-radius: 1em; border: 1px solid rgba(0, 0, 0, .2); box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); } .wj-cell.switch input[type=checkbox]:checked+span:after { left: 1.25em; transition: all 0.3s; background: inherit; }
export function getData(cnt = 100) { var data = [], countries = getCountries(), products = getProducts(), names = getNames(), dt = new Date(), yr = dt.getFullYear(); for (var i = 0; i < cnt; i++) { data.push({ id: i, date: new Date(yr, i % 12, 25, i % 24, i % 60, i % 60), time: new Date(yr, i % 12, 25, i % 24, i % 60, i % 60), country: pickOne(countries), productId: pickOne(products).id, name: [pickOne(names), pickOne(names)], phone: "(" + generateNumber(100, 999) + ") " + generateNumber(100, 999) + "-" + generateNumber(1000, 9999), color: pickOne('Red,Green,Blue,Yellow,Pink,Orange,Gold'.split(',')), amount: Math.random() * 10000, discount: Math.random() / 4, premium: Math.random() > .8 }); } return data; } export function getCountries() { return 'US,Germany,UK,Japan,Italy,Greece'.split(','); } export function getProducts() { let p = 'Andy Capp\'s fries,Barcel,Brannigans,Bugles,Cape Cod Potato Chips,Cheese Flavoured Moments,' + 'Cheetos,Cheez Doodles,Cheez-It,Cheezies,CornNuts,David Sunflower Seeds,Doritos,Frazzles,Frito-Lay,' + 'Fritos,Golden Wonder,Hula Hoops,Kettle Foods,KP Nuts,Kurkure,Lay\'s Stax,McCoys Crisps,' + 'Monster Munch,Munchos,Nobby\'s Nuts,Phileas Fogg,Pirate\'s Booty,Pringles,Ringos,Ruffles,' + 'Salt\'n\' Shake,San Nicasio,Space Raiders,Sun Chips,Smith\'s Crisps,Tudor Crisps,Twiglets,' + 'Twisties,Tyrrells,Tyrrells Apple Chips,Walkers Crisps,Wheat Crunchies,Wise Foods,Wotsits'; return p.split(',').map((name, id) => { return { id: id, name: name }; }); } export function getNames() { return 'Aaron Smith,Paul Johnson,John Richards,Mark Bannon,Sue Wong'.split(','); } function pickOne(arr) { return arr[Math.floor(Math.random() * arr.length)]; } function generateNumber(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } export const data = getData(); export const countries = getCountries(); export const products = getProducts(); export const names = getNames();
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, react: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.grid.immutable': 'npm:@mescius/wijmo.grid.immutable/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js', "@mescius/wijmo.react.chart.analytics": "npm:@mescius/wijmo.react.chart.analytics/index.js", "@mescius/wijmo.react.chart.animation": "npm:@mescius/wijmo.react.chart.animation/index.js", "@mescius/wijmo.react.chart.annotation": "npm:@mescius/wijmo.react.chart.annotation/index.js", "@mescius/wijmo.react.chart.finance.analytics": "npm:@mescius/wijmo.react.chart.finance.analytics/index.js", "@mescius/wijmo.react.chart.finance": "npm:@mescius/wijmo.react.chart.finance/index.js", "@mescius/wijmo.react.chart.hierarchical": "npm:@mescius/wijmo.react.chart.hierarchical/index.js", "@mescius/wijmo.react.chart.interaction": "npm:@mescius/wijmo.react.chart.interaction/index.js", "@mescius/wijmo.react.chart.radar": "npm:@mescius/wijmo.react.chart.radar/index.js", "@mescius/wijmo.react.chart": "npm:@mescius/wijmo.react.chart/index.js", "@mescius/wijmo.react.core": "npm:@mescius/wijmo.react.core/index.js", '@mescius/wijmo.react.chart.map': 'npm:@mescius/wijmo.react.chart.map/index.js', "@mescius/wijmo.react.gauge": "npm:@mescius/wijmo.react.gauge/index.js", "@mescius/wijmo.react.grid.detail": "npm:@mescius/wijmo.react.grid.detail/index.js", "@mescius/wijmo.react.grid.filter": "npm:@mescius/wijmo.react.grid.filter/index.js", "@mescius/wijmo.react.grid.grouppanel": "npm:@mescius/wijmo.react.grid.grouppanel/index.js", '@mescius/wijmo.react.grid.search': 'npm:@mescius/wijmo.react.grid.search/index.js', "@mescius/wijmo.react.grid.multirow": "npm:@mescius/wijmo.react.grid.multirow/index.js", "@mescius/wijmo.react.grid.sheet": "npm:@mescius/wijmo.react.grid.sheet/index.js", '@mescius/wijmo.react.grid.transposed': 'npm:@mescius/wijmo.react.grid.transposed/index.js', '@mescius/wijmo.react.grid.transposedmultirow': 'npm:@mescius/wijmo.react.grid.transposedmultirow/index.js', '@mescius/wijmo.react.grid.immutable': 'npm:@mescius/wijmo.react.grid.immutable/index.js', "@mescius/wijmo.react.grid": "npm:@mescius/wijmo.react.grid/index.js", "@mescius/wijmo.react.input": "npm:@mescius/wijmo.react.input/index.js", "@mescius/wijmo.react.olap": "npm:@mescius/wijmo.react.olap/index.js", "@mescius/wijmo.react.viewer": "npm:@mescius/wijmo.react.viewer/index.js", "@mescius/wijmo.react.nav": "npm:@mescius/wijmo.react.nav/index.js", "@mescius/wijmo.react.base": "npm:@mescius/wijmo.react.base/index.js", '@mescius/wijmo.react.barcode.common': 'npm:@mescius/wijmo.react.barcode.common/index.js', '@mescius/wijmo.react.barcode.composite': 'npm:@mescius/wijmo.react.barcode.composite/index.js', '@mescius/wijmo.react.barcode.specialized': 'npm:@mescius/wijmo.react.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'react': 'npm:react/umd/react.production.min.js', 'react-dom': 'npm:react-dom/umd/react-dom.production.min.js', 'react-dom/client': 'npm:react-dom/umd/react-dom.production.min.js', 'redux': 'npm:redux/dist/redux.min.js', 'react-redux': 'npm:react-redux/dist/react-redux.min.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js', "react-use-event-hook": "npm:react-use-event-hook/dist/esm/useEvent.js", }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'jsx' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);