<!DOCTYPE html>
<html lang="en">
<head>
<title>ag-Grid React Example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style> html, body, #root { margin: 0; padding: 0; height: 100%; } </style>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css"/>
</head>
<body>
<div id="root">Loading ag-Grid React example…</div>
<script>
var appLocation = '';
var boilerplatePath = '';
var systemJsMap = {
"jquery": "https:\/\/unpkg.com\/jquery@3.3.1\/dist\/jquery.js",
"jquery-ui": "https:\/\/unpkg.com\/jquery-ui@1.12.1",
"ag-grid-community":"https:\/\/unpkg.com\/ag-grid-community@19.0.0\/dist\/ag-grid-community.js",
"ag-grid-community\/main":"https:\/\/unpkg.com\/ag-grid-community@19.0.0\/dist\/ag-grid-community.js",
"ag-grid-enterprise":"https:\/\/unpkg.com\/ag-grid-enterprise@19.0.0\/",
"ag-grid-react":"npm:ag-grid-react@19.1.1\/",
"ag-grid-angular":"npm:ag-grid-angular@19.1.1\/",
"ag-grid-vue":"npm:ag-grid-vue@19.1.1\/"
}
</script>
<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script src="https://npmcdn.com/moment@2.14.1"></script>
<script>
System.import('index.jsx').catch( function(err) { console.error(err); })
</script>
</body>
</html>
import React, {Component} from 'react';
export default class CustomDateComponent extends Component {
constructor(props) {
super(props);
//The state of this component is represented of:
// The current date it holds, null by default, null if the date typed by the user is not valid or fields are blank
// The current values that the user types in the input boxes, by default ''
//The textBoxes state is necessary since it can be set from ag-Grid. This can be seen in this example through
// the usage of the button DOB equals to 01/01/2000 in the example page.
this.state = {
date: null,
textBoxes: {
dd: '',
mm: '',
yyyy: ''
}
}
}
render() {
//Inlining styles to make simpler the component
let filterStyle = {
margin: '0px'
};
let ddStyle = {
width: '20px'
};
let mmStyle = {
width: '25px'
};
let yyyyStyle = {
width: '35px'
};
let dividerStyle = {
margin: '3px'
};
let resetStyle = {
padding: '2px',
backgroundColor: 'red',
borderRadius: '3px',
fontSize: '10px',
marginRight: '5px',
color: 'white'
};
return (
<div style={filterStyle}>
<span style={resetStyle} onClick={this.resetDate.bind(this)}>x</span>
<input onInput={this.onDateChanged.bind(this)} ref="dd" placeholder="dd" style={ddStyle}
value={this.state.textBoxes.dd} maxLength="2"/>
<span style={dividerStyle}>/</span>
<input onInput={this.onDateChanged.bind(this)} ref="mm" placeholder="mm" style={mmStyle}
value={this.state.textBoxes.mm} maxLength="2"/>
<span style={dividerStyle}>/</span>
<input onInput={this.onDateChanged.bind(this)} ref="yyyy" placeholder="yyyy" style={yyyyStyle}
value={this.state.textBoxes.yyyy} maxLength="4"/>
</div>
);
}
//*********************************************************************************
// METHODS REQUIRED BY AG-GRID
//*********************************************************************************
getDate() {
//ag-grid will call us here when in need to check what the current date value is hold by this
//component.
return this.state.date;
}
setDate(date) {
//ag-grid will call us here when it needs this component to update the date that it holds.
this.setState({
date,
textBoxes: {
dd: date ? date.getDate() : '',
mm: date ? date.getMonth() + 1 : '',
yyyy: date ? date.getFullYear() : ''
}
})
}
//*********************************************************************************
// LINKS THE INTERNAL STATE AND AG-GRID
//*********************************************************************************
updateAndNotifyAgGrid(date, textBoxes) {
this.setState({
date: date,
textBoxes: textBoxes
},
//Callback after the state is set. This is where we tell ag-grid that the date has changed so
//it will proceed with the filtering and we can then expect ag-Grid to call us back to getDate
this.props.onDateChanged
);
}
//*********************************************************************************
// LINKING THE UI, THE STATE AND AG-GRID
//*********************************************************************************
resetDate() {
let date = null;
let textBoxes = {
dd: '',
mm: '',
yyyy: '',
};
this.updateAndNotifyAgGrid(date, textBoxes)
}
onDateChanged() {
let date = this.parseDate(this.refs.dd.value, this.refs.mm.value, this.refs.yyyy.value);
let textBoxes = {
dd: this.refs.dd.value,
mm: this.refs.mm.value,
yyyy: this.refs.yyyy.value,
};
this.updateAndNotifyAgGrid(date, textBoxes)
}
//*********************************************************************************
// INTERNAL LOGIC
//*********************************************************************************
parseDate(dd, mm, yyyy) {
//If any of the three input date fields are empty, stop and return null
if (dd.trim() === '' || mm.trim() === '' || yyyy.trim() === '') {
return null;
}
let day = Number(dd);
let month = Number(mm);
let year = Number(yyyy);
let date = new Date(year, month - 1, day);
//If the date is not valid
if (isNaN(date.getTime())) {
return null;
}
//Given that new Date takes any garbage in, it is possible for the user to specify a new Date
//like this (-1, 35, 1) and it will return a valid javascript date. In this example, it will
//return Sat Dec 01 1 00:00:00 GMT+0000 (GMT) - Go figure...
//To ensure that we are not letting non sensical dates to go through we check that the resultant
//javascript date parts (month, year and day) match the given date fields provided as parameters.
//If the javascript date parts don't match the provided fields, we assume that the input is non
//sensical... ie: Day=-1 or month=14, if this is the case, we return null
//This also protects us from non sensical dates like dd=31, mm=2 of any year
if (date.getDate() != day || date.getMonth() + 1 != month || date.getFullYear() != year) {
return null;
}
return date;
}
}
import React, { Component } from "react";
import { render } from "react-dom";
import { AgGridReact } from "ag-grid-react";
import CustomDateComponent from "./customDateComponent.jsx";
import JQueryDateComponent from "./JQueryDateComponent.jsx";
class GridExample extends Component {
constructor(props) {
super(props);
this.state = {
columnDefs: [
{
headerName: "Athlete",
field: "athlete",
width: 150
},
{
headerName: "Date",
field: "date",
width: 160,
filter: "agDateColumnFilter",
filterParams: {
comparator: function(filterLocalDateAtMidnight, cellValue) {
var dateAsString = cellValue;
var dateParts = dateAsString.split("/");
var cellDate = new Date(Number(dateParts[2]), Number(dateParts[1]) - 1, Number(dateParts[0]));
if (filterLocalDateAtMidnight.getTime() === cellDate.getTime()) {
return 0;
}
if (cellDate < filterLocalDateAtMidnight) {
return -1;
}
if (cellDate > filterLocalDateAtMidnight) {
return 1;
}
}
}
},
{
headerName: "Sport",
field: "sport",
width: 110
}
],
frameworkComponents: {
// agDateInput: CustomDateComponent
agDateInput: JQueryDateComponent
},
rowData: []
};
}
onGridReady(params) {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
const httpRequest = new XMLHttpRequest();
const updateData = data => {
this.setState({ rowData: data });
};
httpRequest.open(
"GET",
"https://raw.githubusercontent.com/ag-grid/ag-grid/master/packages/ag-grid-docs/src/olympicWinners.json"
);
httpRequest.send();
httpRequest.onreadystatechange = () => {
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
updateData(JSON.parse(httpRequest.responseText));
}
};
}
render() {
return (
<div style={{ width: "100%", height: "100%" }}>
<div
id="myGrid"
style={{
boxSizing: "border-box",
height: "450px",
width: "100%"
}}
className="ag-theme-material"
>
<AgGridReact
columnDefs={this.state.columnDefs}
enableFilter={true}
frameworkComponents={this.state.frameworkComponents}
onGridReady={this.onGridReady.bind(this)}
rowData={this.state.rowData}
/>
</div>
</div>
);
}
}
render(<GridExample />, document.querySelector("#root"));
.filter {
margin: 0;
}
.dd {
width: 20px !important;
}
.mm {
width: 25px !important;
}
.yyyy {
width: 35px !important;
}
.divider {
margin: 0;
padding: 0;
}
.reset {
padding: 2px;
background-color: red;
border-radius: 3px;
font-size: 10px;
margin-right: 5px;
color: white;
}
(function(global) {
// simplified version of Object.assign for es3
function assign() {
var result = {};
for (var i = 0, len = arguments.length; i < len; i++) {
var arg = arguments[i];
for (var prop in arg) {
result[prop] = arg[prop];
}
}
return result;
}
System.config({
transpiler: 'plugin-babel',
defaultExtension: 'js',
paths: {
'npm:': 'https://unpkg.com/'
},
map: assign(
{
// babel transpiler
'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js',
'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js',
// react
react: 'npm:react@16.0.0',
'react-dom': 'npm:react-dom@16.0.0',
'react-dom-factories': 'npm:react-dom-factories',
redux: 'npm:redux@3.6.0',
'react-redux': 'npm:react-redux@5.0.6',
'prop-types': 'npm:prop-types',
app: appLocation + 'app'
},
systemJsMap
), // systemJsMap comes from index.html
packages: {
react: {
main: './umd/react.production.min.js'
},
'react-dom': {
main: './umd/react-dom.production.min.js'
},
'prop-types': {
main: './prop-types.min.js',
defaultExtension: 'js'
},
redux: {
main: './dist/redux.min.js',
defaultExtension: 'js'
},
'react-redux': {
main: './dist/react-redux.min.js',
defaultExtension: 'js'
},
app: {
defaultExtension: 'jsx'
},
'ag-grid-react': {
main: './main.js',
defaultExtension: 'js'
},
'ag-grid-enterprise': {
main: './main.js',
defaultExtension: 'js'
}
},
meta: {
'*.jsx': {
babelOptions: {
react: true
}
}
}
});
})(this);
import React, {Component} from 'react';
import $ from 'jquery';
import 'jquery-ui/ui/core';
import 'jquery-ui/ui/widgets/datepicker';
export default class JQueryDateComponent extends Component {
constructor(props) {
super(props);
//The state of this component is represented of:
// The current date it holds, null by default, null if the field is blank
this.state = {
date: null
};
}
componentDidMount() {
$(this.refs.input).datepicker({
dateFormat: "yy-mm-dd",
onSelect: this.onDateChanged.bind(this)
});
}
componentWillUnmount() {
$(this.refs.input).datepicker('destroy');
}
render() {
const props = this.props;
return (
<div>Date: <input ref="input" {...props} /></div>
)
}
//*********************************************************************************
// METHODS REQUIRED BY AG-GRID
//*********************************************************************************
getDate() {
//ag-grid will call us here when in need to check what the current date value is hold by this component.
return this.state.date;
}
setDate(date) {
//ag-grid will call us here when it needs this component to update the date that it holds.
this.setState({
date
});
}
//*********************************************************************************
// LINKS THE INTERNAL STATE AND AG-GRID
//*********************************************************************************
updateAndNotifyAgGrid(date) {
this.setState({
date: date
},
//Callback after the state is set. This is where we tell ag-grid that the date has changed so
//it will proceed with the filtering and we can then expect ag-Grid to call us back to getDate
this.props.onDateChanged
);
}
//*********************************************************************************
// LINKING THE UI, THE STATE AND AG-GRID
//*********************************************************************************
onDateChanged() {
let date = moment(this.refs.input.value);
if (date !== this.state.date) {
this.updateAndNotifyAgGrid(date.toDate());
}
}
}