AG-1294 Sweep framework examples & update versions Sprint IV
This commit is contained in:
29
package.json
29
package.json
@@ -38,39 +38,38 @@
|
||||
},
|
||||
"homepage": "http://www.ag-grid.com/",
|
||||
"devDependencies": {
|
||||
"babel-core": "6.24.x",
|
||||
"babel-core": "6.26.x",
|
||||
"babel-loader": "6.4.x",
|
||||
"babel-preset-es2015": "6.24.x",
|
||||
"babel-preset-react": "6.24.x",
|
||||
"babel-preset-stage-0": "6.24.x",
|
||||
"babel-preset-stage-1": "6.24.x",
|
||||
"css-loader": "0.23.x",
|
||||
"css-loader": "0.28.x",
|
||||
"mkdirp": "0.5.1",
|
||||
"ncp": "2.0.0",
|
||||
"prop-types": "15.6.0",
|
||||
"rimraf": "2.5.x",
|
||||
"style-loader": "0.13.x",
|
||||
"webpack": "1.12.x",
|
||||
"webpack-dev-server": "1.14.x",
|
||||
"style-loader": "0.19.x",
|
||||
"webpack": "1.15.x",
|
||||
"webpack-dev-server": "1.15.x",
|
||||
"gulp": "3.9.x",
|
||||
"gulp-typescript": "3.1.x",
|
||||
"gulp-typescript": "3.2.x",
|
||||
"merge2": "1.0.x",
|
||||
"typescript": "2.3.x"
|
||||
"typescript": "2.6.2",
|
||||
"file-loader": "0.11.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ag-grid": "^14.0.0",
|
||||
"ag-grid-enterprise": "^14.0.0",
|
||||
"ag-grid-react": "^14.0.0",
|
||||
"ag-grid": "^15.0.0",
|
||||
"ag-grid-enterprise": "^15.0.0",
|
||||
"ag-grid-react": "^15.0.0",
|
||||
"bootstrap": "3.3.7",
|
||||
"d3": "4.9.1",
|
||||
"file-loader": "0.11.1",
|
||||
"lodash": "4.17.4",
|
||||
"react": "16.0.0",
|
||||
"react-dom": "16.0.0",
|
||||
"react": "16.2.x",
|
||||
"react-dom": "16.2.x",
|
||||
"react-dom-factories": "1.0.2",
|
||||
"react-redux": "5.0.x",
|
||||
"react-router-dom": "4.2.x",
|
||||
"redux": "3.6.x",
|
||||
"url-search-params-polyfill": "1.2.0"
|
||||
"redux": "3.7.x"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,33 +3,13 @@ import {Redirect, Route, Switch} from "react-router-dom";
|
||||
|
||||
import NavItem from "./NavItem";
|
||||
|
||||
import DynamicComponentsExample from "./dynamicComponentExample/DynamicComponentsExample";
|
||||
import RichGridExample from "./richGridExample/RichGridExample";
|
||||
import RichGridDeclarativeExample from "./richGridDeclarativeExample/RichGridDeclarativeExample";
|
||||
import RichComponentsExample from "./richComponentExample/RichComponentsExample";
|
||||
import EditorComponentsExample from "./editorComponentExample/EditorComponentsExample";
|
||||
import PinnedRowComponentExample from "./pinnedRowExample/PinnedRowComponentExample";
|
||||
import FullWidthComponentExample from "./fullWidthExample/FullWidthComponentExample";
|
||||
import GroupedRowInnerRendererComponentExample from "./groupedRowInnerRendererExample/GroupedRowInnerRendererComponentExample";
|
||||
import FilterComponentExample from "./filterComponentExample/FilterComponentExample";
|
||||
import SimpleReduxExample from "./simpleReduxExample/SimpleReduxExample";
|
||||
import FloatingFilterGridExample from "./floatingFilter/FloatingFilterGridExample";
|
||||
import SimpleReduxDynamicExample from "./simpleReduxDynamicComponentExample/SimpleReduxExample";
|
||||
|
||||
const SideBar = () => (
|
||||
<div style={{float: "left", width: 335, marginRight: 25}}>
|
||||
<ul className="nav nav-pills nav-stacked">
|
||||
<NavItem to='/rich-grid'>Rich Grid Example</NavItem>
|
||||
<NavItem to='/rich-grid-declarative'>Rich Grid with Declarative Markup</NavItem>
|
||||
<NavItem to='/dynamic'>Dynamic React Component Example</NavItem>
|
||||
<NavItem to='/rich-dynamic'>Dynamic React Components - Richer Example</NavItem>
|
||||
<NavItem to='/editor'>Cell Editor Component Example</NavItem>
|
||||
<NavItem to='/floating-row'>Floating Row Renderer Example</NavItem>
|
||||
<NavItem to='/full-width'>Full Width Renderer Example</NavItem>
|
||||
<NavItem to='/group-row'>Grouped Row Inner Renderer Example</NavItem>
|
||||
<NavItem to='/filter'>Filters Component Example</NavItem>
|
||||
<NavItem to='/floating-filter'>Floating Filters</NavItem>
|
||||
<NavItem to='/simple-redux'>Simple Redux Example</NavItem>
|
||||
<NavItem to='/simple-redux-dynamic'>Simple Redux Dynamic Component Example</NavItem>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -42,18 +22,8 @@ class App extends Component {
|
||||
<SideBar/>
|
||||
<div style={{float: "left"}}>
|
||||
<Switch>
|
||||
<Redirect from="/" exact to="/rich-grid"/>
|
||||
<Route exact path='/rich-grid' component={RichGridExample}/>
|
||||
<Redirect from="/" exact to="/rich-grid-declarative"/>
|
||||
<Route exact path='/rich-grid-declarative' component={RichGridDeclarativeExample}/>
|
||||
<Route exact path='/dynamic' component={DynamicComponentsExample}/>
|
||||
<Route exact path='/rich-dynamic' component={RichComponentsExample}/>
|
||||
<Route exact path='/editor' component={EditorComponentsExample}/>
|
||||
<Route exact path='/floating-row' component={PinnedRowComponentExample}/>
|
||||
<Route exact path='/full-width' component={FullWidthComponentExample}/>
|
||||
<Route exact path='/group-row' component={GroupedRowInnerRendererComponentExample}/>
|
||||
<Route exact path='/filter' component={FilterComponentExample}/>
|
||||
<Route exact path='/floating-filter' component={FloatingFilterGridExample}/>
|
||||
<Route exact path='/simple-redux' component={SimpleReduxExample}/>
|
||||
<Route exact path='/simple-redux-dynamic' component={SimpleReduxDynamicExample}/>
|
||||
</Switch>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class ChildMessageRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
invokeParentMethod = () => {
|
||||
let rowIndex = this.props.node.rowIndex;
|
||||
let headerName = this.props.colDef.headerName;
|
||||
|
||||
this.props.context.componentParent.methodFromParent(`Row: ${rowIndex}, Col: ${headerName}`)
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span><button style={{height: 20, lineHeight: 0.5}} onClick={this.invokeParentMethod} className="btn btn-info">Invoke Parent</button></span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class CubeRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: this.valueSquared()
|
||||
};
|
||||
}
|
||||
|
||||
valueSquared() {
|
||||
return this.props.value * this.props.value * this.props.value;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.state.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class CurrencyRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: props.value
|
||||
}
|
||||
}
|
||||
|
||||
static formatValueToCurrency(currency, value) {
|
||||
return `${currency}${value}`
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
refresh(params) {
|
||||
if(params.value !== this.state.value) {
|
||||
this.setState({
|
||||
value: params.value.toFixed(2)
|
||||
})
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{CurrencyRenderer.formatValueToCurrency('EUR', this.state.value)}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,162 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import SquareRenderer from "./SquareRenderer";
|
||||
import CubeRenderer from "./CubeRenderer";
|
||||
import ParamsRenderer from "./ParamsRenderer";
|
||||
import CurrencyRenderer from "./CurrencyRenderer";
|
||||
import ChildMessageRenderer from "./ChildMessageRenderer";
|
||||
|
||||
export default class DynamicComponentsExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {
|
||||
context: {
|
||||
componentParent: this
|
||||
}
|
||||
},
|
||||
|
||||
rowData: DynamicComponentsExample.createRowData(),
|
||||
|
||||
columnDefs: DynamicComponentsExample.createColumnDefs()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
onGridReady = (params) => {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
};
|
||||
|
||||
methodFromParent(cell) {
|
||||
alert(`Parent Component Method from ${cell}!`);
|
||||
}
|
||||
|
||||
refreshEvenRowsCurrencyData = () => {
|
||||
this.gridApi.forEachNode(rowNode => {
|
||||
if (rowNode.data.value % 2 === 0) {
|
||||
rowNode.setDataValue('currency', rowNode.data.value + Number(Math.random().toFixed(2)))
|
||||
}
|
||||
});
|
||||
|
||||
this.gridApi.refreshCells({
|
||||
columns: ['currency']
|
||||
})
|
||||
};
|
||||
|
||||
static createColumnDefs() {
|
||||
return [
|
||||
{headerName: "Row", field: "row", width: 100},
|
||||
{
|
||||
headerName: "Square",
|
||||
field: "value",
|
||||
cellRendererFramework: SquareRenderer,
|
||||
editable: true,
|
||||
colId: "square",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
headerName: "Cube",
|
||||
field: "value",
|
||||
cellRendererFramework: CubeRenderer,
|
||||
colId: "cube",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
headerName: "Row Params",
|
||||
field: "row",
|
||||
cellRendererFramework: ParamsRenderer,
|
||||
colId: "params",
|
||||
width: 215
|
||||
},
|
||||
{
|
||||
headerName: "Currency",
|
||||
field: "currency",
|
||||
cellRendererFramework: CurrencyRenderer,
|
||||
colId: "currency",
|
||||
width: 135
|
||||
},
|
||||
{
|
||||
headerName: "Child/Parent",
|
||||
field: "value",
|
||||
cellRendererFramework: ChildMessageRenderer,
|
||||
colId: "params",
|
||||
width: 120
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
static createRowData() {
|
||||
let rowData = [];
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
rowData.push({
|
||||
row: "Row " + i,
|
||||
value: i,
|
||||
currency: 1 + Number(Math.random()).toFixed(2)
|
||||
});
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 900}}
|
||||
className="ag-fresh">
|
||||
<h1>Dynamic React Component Example</h1>
|
||||
<button onClick={this.refreshEvenRowsCurrencyData} style={{marginBottom: 10}}
|
||||
className="btn btn-primary">Refresh Even Row Currency Data
|
||||
</button>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
gridOptions={this.state.gridOptions}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
<div className="row">
|
||||
<div className="col-sm-12"><h1>Dynamic React Component Example</h1></div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<h5>This example demonstrates Dynamic React Components with ag-Grid, Parent/Child Communication
|
||||
(cell component to parent grid component), as well as
|
||||
dynamic data updates of the <code>Currency</code> column.</h5>
|
||||
<p><span style={{fontWeight: "bold"}}>Square, Cube, Row Params, Currency and Child/Parent</span>:
|
||||
React Components within the Grid</p>
|
||||
<p><span style={{fontWeight: "bold"}}>Currency (Pipe)</span>: An React Component mimicking a
|
||||
Currency Pipe, dynamically updated with the button above.</p>
|
||||
<p><span style={{fontWeight: "bold"}}>Child/Parent</span>: Demonstrates the Child Cell Component
|
||||
communicating with the Parent Grid Component.</p>
|
||||
<p><span style={{fontWeight: "bold"}}>Refresh Even Row Currency Data</span>: Dynamically Updates
|
||||
Event Rows Currency Value. Only the Currency column will be re-rendered.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">React Functionality</h4>
|
||||
<p className="card-text">Utilise React Components within ag-Grid</p>
|
||||
<a target="_blank" href="https://www.ag-grid.com/best-react-data-grid/?framework=react"
|
||||
className="btn btn-primary">React with ag-Grid</a>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com/javascript-grid-cell-rendering-components/?framework=react"
|
||||
className="btn btn-primary">React Renderers</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-data-update/"
|
||||
className="btn btn-primary">Updating Data</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class ParamsRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>Field: {this.props.colDef.field}, Value: {this.props.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class SquareRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: this.valueSquared()
|
||||
};
|
||||
}
|
||||
|
||||
valueSquared() {
|
||||
return this.props.value * this.props.value;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.state.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,132 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import MoodRenderer from "./MoodRenderer";
|
||||
import MoodEditor from "./MoodEditor";
|
||||
import NumericEditor from "./NumericEditor";
|
||||
|
||||
export default class EditorComponentsExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
rowData: EditorComponentsExample.createRowData(),
|
||||
columnDefs: EditorComponentsExample.createColumnDefs()
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
static createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Name",
|
||||
field: "name",
|
||||
width: 300,
|
||||
editable: true,
|
||||
cellEditor: 'richSelect',
|
||||
cellEditorParams: {
|
||||
values: [
|
||||
"Bob",
|
||||
"Harry",
|
||||
"Sally",
|
||||
"Mary",
|
||||
"John",
|
||||
"Jack",
|
||||
"Sue",
|
||||
"Sean",
|
||||
"Niall",
|
||||
"Albert",
|
||||
"Fred",
|
||||
"Jenny",
|
||||
"Larry"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
headerName: "Mood",
|
||||
field: "mood",
|
||||
cellRendererFramework: MoodRenderer,
|
||||
cellEditorFramework: MoodEditor,
|
||||
editable: true,
|
||||
width: 250
|
||||
},
|
||||
{
|
||||
headerName: "Numeric",
|
||||
field: "number",
|
||||
cellEditorFramework: NumericEditor,
|
||||
editable: true,
|
||||
width: 250
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
static createRowData() {
|
||||
return [
|
||||
{name: "Bob", mood: "Happy", number: 10},
|
||||
{name: "Harry", mood: "Sad", number: 3},
|
||||
{name: "Sally", mood: "Happy", number: 20},
|
||||
{name: "Mary", mood: "Sad", number: 5},
|
||||
{name: "John", mood: "Happy", number: 15},
|
||||
{name: "Jack", mood: "Happy", number: 25},
|
||||
{name: "Sue", mood: "Sad", number: 43},
|
||||
{name: "Sean", mood: "Sad", number: 1335},
|
||||
{name: "Niall", mood: "Happy", number: 2},
|
||||
{name: "Alberto", mood: "Happy", number: 123},
|
||||
{name: "Fred", mood: "Sad", number: 532},
|
||||
{name: "Jenny", mood: "Happy", number: 34},
|
||||
{name: "Larry", mood: "Happy", number: 13},
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 370, width: 900}}
|
||||
className="ag-fresh">
|
||||
<h1>Cell Editor Component Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
<div className="row">
|
||||
<div className="col-sm-12"><h1>Cell Editor Component Example</h1></div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<h5>This example demonstrates React Editor Components within ag-Grid, as well as an example using the built in Rich Select editor.</h5>
|
||||
<p><span style={{fontWeight: "bold"}}>Name</span>: Utilises the built in <code>RichSelect</code> editor</p>
|
||||
<p><span style={{fontWeight: "bold"}}>Mood</span>: A Custom React Editor demonstrating popup functionality, with full keyboard control.</p>
|
||||
<p><span style={{fontWeight: "bold"}}>Numeric</span>: A Custom React Editor demonstrating pre & post validation. Only numeric characters are allowed,
|
||||
and numbers greater than 1000000 will be rejected.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">React Functionality</h4>
|
||||
<p className="card-text">Utilise React Components within ag-Grid</p>
|
||||
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-cell-editing/?framework=react" className="btn btn-primary">Cell Editing</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-cell-editor/?framework=react" className="btn btn-primary">Editor Components</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com/best-react-data-grid/?framework=react" className="btn btn-primary">React with ag-Grid</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-cell-editor/?framework=react#reactCellEditing" className="btn btn-primary">React Editor Components</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,120 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
export default class MoodEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onHappyClick = this.onHappyClick.bind(this);
|
||||
this.onSadClick = this.onSadClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
happy: false
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setHappy(this.props.value === "Happy");
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.refs.container.addEventListener('keydown', this.checkAndToggleMoodIfLeftRight);
|
||||
this.focus();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.refs.container.removeEventListener('keydown', this.checkAndToggleMoodIfLeftRight);
|
||||
}
|
||||
|
||||
checkAndToggleMoodIfLeftRight = (event) => {
|
||||
if ([37, 39].indexOf(event.keyCode) > -1) { // left and right
|
||||
this.toggleMood();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
focus() {
|
||||
setTimeout(() => {
|
||||
let container = ReactDOM.findDOMNode(this.refs.container);
|
||||
if (container) {
|
||||
container.focus();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.state.happy ? "Happy" : "Sad";
|
||||
}
|
||||
|
||||
isPopup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
setHappy(happy) {
|
||||
this.setState({
|
||||
happy
|
||||
});
|
||||
}
|
||||
|
||||
onHappyClick() {
|
||||
this.setState({
|
||||
happy: true
|
||||
},
|
||||
() => this.props.api.stopEditing()
|
||||
);
|
||||
}
|
||||
|
||||
onSadClick() {
|
||||
this.setState({
|
||||
happy: false
|
||||
},
|
||||
() => this.props.api.stopEditing()
|
||||
);
|
||||
}
|
||||
|
||||
toggleMood() {
|
||||
this.setHappy(!this.state.happy);
|
||||
}
|
||||
|
||||
render() {
|
||||
let mood = {
|
||||
borderRadius: 15,
|
||||
border: "1px solid grey",
|
||||
background: "#e6e6e6",
|
||||
padding: 15,
|
||||
textAlign: "center",
|
||||
display: "inline-block"
|
||||
};
|
||||
|
||||
let unselected = {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
border: "1px solid transparent",
|
||||
padding: 4
|
||||
};
|
||||
|
||||
let selected = {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
border: "1px solid lightgreen",
|
||||
padding: 4
|
||||
};
|
||||
|
||||
let happyStyle = this.state.happy ? selected : unselected;
|
||||
let sadStyle = !this.state.happy ? selected : unselected;
|
||||
|
||||
return (
|
||||
<div ref="container"
|
||||
style={mood}
|
||||
tabIndex={1} // important - without this the keypresses wont be caught
|
||||
>
|
||||
<img src="images/smiley.png" onClick={this.onHappyClick} style={happyStyle}/>
|
||||
<img src="images/smiley-sad.png" onClick={this.onSadClick} style={sadStyle}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class MoodRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setMood(this.props.value)
|
||||
}
|
||||
|
||||
refresh(params) {
|
||||
this.setMood(params.value);
|
||||
}
|
||||
|
||||
setMood(mood) {
|
||||
this.setState({
|
||||
imgForMood: mood === 'Happy' ? 'images/smiley.png' : 'images/smiley-sad.png'
|
||||
})
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<img width="20px" src={this.state.imgForMood}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class NumericEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// if the character pressed to start editing isn't numeric we set this flag, which will mean editing wont be initiated
|
||||
this.cancelBeforeStart = this.props.charPress && ('1234567890'.indexOf(this.props.charPress) < 0);
|
||||
|
||||
let value = this.props.value;
|
||||
if (!this.cancelBeforeStart && this.props.charPress) {
|
||||
value = value + this.props.charPress;
|
||||
}
|
||||
|
||||
this.state = {
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.refs.input.addEventListener('keydown', this.onKeyDown);
|
||||
this.focus();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.refs.input.removeEventListener('keydown', this.onKeyDown);
|
||||
}
|
||||
|
||||
// componentDidUpdate() {
|
||||
// this.focus();
|
||||
// }
|
||||
|
||||
focus() {
|
||||
if (!this.cancelBeforeStart) {
|
||||
setTimeout(() => {
|
||||
this.refs.input.focus();
|
||||
this.refs.input.setSelectionRange(this.refs.input.value.length, this.refs.input.value.length);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.state.value;
|
||||
}
|
||||
|
||||
isCancelBeforeStart() {
|
||||
return this.cancelBeforeStart;
|
||||
}
|
||||
|
||||
// will reject the number if it greater than 1,000,000
|
||||
// not very practical, but demonstrates the method.
|
||||
isCancelAfterEnd() {
|
||||
return this.state.value > 1000000;
|
||||
};
|
||||
|
||||
handleChange = (event) => {
|
||||
this.setState({value: event.target.value});
|
||||
};
|
||||
|
||||
onKeyDown = (event) => {
|
||||
// allow back and forth navigation, as well as editing
|
||||
if (NumericEditor.isAllowableKeypress(event)) {
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
// if not a numeral, then reject the keypress
|
||||
if (!NumericEditor.isKeyPressedNumeric(event)) {
|
||||
if (event.preventDefault) event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
static isAllowableKeypress(event) {
|
||||
// left, right, backspace & delete
|
||||
return [37, 39, 46, 8].indexOf(event.keyCode) > -1;
|
||||
}
|
||||
|
||||
static getCharCodeFromEvent(event) {
|
||||
event = event || window.event;
|
||||
return (typeof event.which === "undefined") ? event.keyCode : event.which;
|
||||
}
|
||||
|
||||
static isCharNumeric(charStr) {
|
||||
return !!/\d/.test(charStr);
|
||||
}
|
||||
|
||||
static isKeyPressedNumeric(event) {
|
||||
const charCode = NumericEditor.getCharCodeFromEvent(event);
|
||||
const charStr = event.key ? event.key : String.fromCharCode(charCode);
|
||||
return this.isCharNumeric(charStr);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<input ref="input"
|
||||
value={this.state.value}
|
||||
onChange={this.handleChange}
|
||||
style={{width: "100%",padding:0,margin:-1}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
import PartialMatchFilter from "./PartialMatchFilter";
|
||||
|
||||
export default class FilterComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
rowData: FilterComponentExample.createRowData(),
|
||||
columnDefs: FilterComponentExample.createColumnDefs(),
|
||||
};
|
||||
}
|
||||
|
||||
onGridReady = (params) => {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
};
|
||||
|
||||
onClicked = () => {
|
||||
this.gridApi.getFilterInstance("name").getFrameworkComponentInstance().componentMethod("Hello World!");
|
||||
};
|
||||
|
||||
static createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
field: "row",
|
||||
width: 400,
|
||||
suppressMenu: true
|
||||
},
|
||||
{
|
||||
headerName: "Filter Component",
|
||||
field: "name",
|
||||
filterFramework: PartialMatchFilter,
|
||||
width: 400,
|
||||
menuTabs: ['filterMenuTab']
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
static createRowData() {
|
||||
return [
|
||||
{"row": "Row 1", "name": "Michael Phelps"},
|
||||
{"row": "Row 2", "name": "Natalie Coughlin"},
|
||||
{"row": "Row 3", "name": "Aleksey Nemov"},
|
||||
{"row": "Row 4", "name": "Alicia Coutts"},
|
||||
{"row": "Row 5", "name": "Missy Franklin"},
|
||||
{"row": "Row 6", "name": "Ryan Lochte"},
|
||||
{"row": "Row 7", "name": "Allison Schmitt"},
|
||||
{"row": "Row 8", "name": "Natalie Coughlin"},
|
||||
{"row": "Row 9", "name": "Ian Thorpe"},
|
||||
{"row": "Row 10", "name": "Bob Mill"},
|
||||
{"row": "Row 11", "name": "Willy Walsh"},
|
||||
{"row": "Row 12", "name": "Sarah McCoy"},
|
||||
{"row": "Row 13", "name": "Jane Jack"},
|
||||
{"row": "Row 14", "name": "Tina Wills"}
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 900}}
|
||||
className="ag-fresh">
|
||||
<h1>Filter Component Example</h1>
|
||||
<button style={{marginBottom: 10}} onClick={this.onClicked} className="btn btn-primary">Filter Instance
|
||||
Method
|
||||
</button>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
enableFilter
|
||||
suppressMenuHide
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
<h4>The filter on the Filter Component column uses a Custom React Filter Component</h4>
|
||||
<p>This filter will allow partial matches - for example enter "m p" which will match Michael Phelps.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,83 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class PartialMatchFilter extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
text: ''
|
||||
};
|
||||
|
||||
this.valueGetter = this.props.valueGetter;
|
||||
}
|
||||
|
||||
isFilterActive() {
|
||||
return this.state.text !== null && this.state.text !== undefined && this.state.text !== '';
|
||||
}
|
||||
|
||||
doesFilterPass(params) {
|
||||
return this.state.text.toLowerCase()
|
||||
.split(" ")
|
||||
.every((filterWord) => {
|
||||
return this.valueGetter(params.node).toString().toLowerCase().indexOf(filterWord) >= 0;
|
||||
});
|
||||
}
|
||||
|
||||
getModel() {
|
||||
return {value: this.state.text};
|
||||
}
|
||||
|
||||
setModel(model) {
|
||||
this.state.text = model ? model.value : '';
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
focus() {
|
||||
setTimeout(() => {
|
||||
if (this.refs.input) {
|
||||
this.refs.input.focus();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
componentMethod(message) {
|
||||
alert(`Alert from PartialMatchFilterComponent ${message}`);
|
||||
}
|
||||
|
||||
onChange = (event) => {
|
||||
let newValue = event.target.value;
|
||||
if (this.state.text !== newValue) {
|
||||
this.setState({
|
||||
text: newValue
|
||||
}, () => {
|
||||
// wait for the state to be applied, then let the grid know about the change
|
||||
this.props.filterChangedCallback();
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
console.log("render");
|
||||
let style = {
|
||||
border: "2px solid #22ff22",
|
||||
borderRadius: "5px",
|
||||
backgroundColor: "#bbffbb",
|
||||
width: "200px",
|
||||
height: "50px"
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
Filter: <input style={{height: "20px"}}
|
||||
ref="input"
|
||||
value={this.state.text}
|
||||
onChange={this.onChange}
|
||||
className="form-control"/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,134 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import SlidingFloatingFilter from "./SlidingFloatingFilter";
|
||||
|
||||
export default class FloatingFilterGridExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
columnDefs: FloatingFilterGridExample.createColumnDefs(),
|
||||
rowData: FloatingFilterGridExample.createRowData()
|
||||
}
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
static createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
field: "country",
|
||||
suppressFilter: true
|
||||
},
|
||||
{
|
||||
field: "language",
|
||||
suppressFilter: true
|
||||
},
|
||||
{
|
||||
field: "name",
|
||||
suppressFilter: true
|
||||
},
|
||||
{
|
||||
field: "gold",
|
||||
floatingFilterComponentFramework: SlidingFloatingFilter,
|
||||
floatingFilterComponentParams: {
|
||||
maxValue: 7,
|
||||
suppressFilterButton: true
|
||||
},
|
||||
filter: 'number',
|
||||
suppressMenu: false
|
||||
},
|
||||
{
|
||||
field: "silver",
|
||||
filter: 'number',
|
||||
floatingFilterComponentFramework: SlidingFloatingFilter,
|
||||
floatingFilterComponentParams: {
|
||||
maxValue: 5,
|
||||
suppressFilterButton: true
|
||||
},
|
||||
suppressMenu: false
|
||||
},
|
||||
{
|
||||
field: "bronze",
|
||||
filter: 'number',
|
||||
floatingFilterComponentFramework: SlidingFloatingFilter,
|
||||
floatingFilterComponentParams: {
|
||||
maxValue: 10,
|
||||
suppressFilterButton: true
|
||||
},
|
||||
suppressMenu: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
static createRowData() {
|
||||
return [
|
||||
{country: "United States", language: "English", name: "Bob", gold: 1, silver: 3, bronze: 0},
|
||||
{country: "United States", language: "English", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "United States", language: "English", name: "Sue", gold: 3, silver: 0, bronze: 1},
|
||||
{country: "United Kingdom", language: "English", name: "Mary", gold: 1, silver: 1, bronze: 2},
|
||||
{country: "United Kingdom", language: "English", name: "Tess", gold: 2, silver: 1, bronze: 1},
|
||||
{country: "United Kingdom", language: "English", name: "John", gold: 0, silver: 2, bronze: 1},
|
||||
{country: "Jamaica", language: "English", name: "Bob", gold: 4, silver: 1, bronze: 2},
|
||||
{country: "Jamaica", language: "English", name: "Jack", gold: 3, silver: 1, bronze: 2},
|
||||
{country: "Jamaica", language: "English", name: "Mary", gold: 1, silver: 1, bronze: 2},
|
||||
{country: "South Africa", language: "English", name: "Bob", gold: 4, silver: 0, bronze: 1},
|
||||
{country: "South Africa", language: "English", name: "Jack", gold: 3, silver: 0, bronze: 1},
|
||||
{country: "South Africa", language: "English", name: "Mary", gold: 5, silver: 3, bronze: 1},
|
||||
{country: "South Africa", language: "English", name: "John", gold: 2, silver: 3, bronze: 1},
|
||||
{country: "New Zealand", language: "English", name: "Bob", gold: 5, silver: 3, bronze: 10},
|
||||
{country: "New Zealand", language: "English", name: "Jack", gold: 1, silver: 1, bronze: 1},
|
||||
{country: "New Zealand", language: "English", name: "Sue", gold: 1, silver: 3, bronze: 1},
|
||||
{country: "Australia", language: "English", name: "Mary", gold: 1, silver: 1, bronze: 3},
|
||||
{country: "Australia", language: "English", name: "Tess", gold: 2, silver: 1, bronze: 1},
|
||||
{country: "Australia", language: "English", name: "John", gold: 3, silver: 2, bronze: 1},
|
||||
{country: "Canada", language: "English", name: "Bob", gold: 7, silver: 5, bronze: 3},
|
||||
{country: "Canada", language: "English", name: "Jack", gold: 2, silver: 1, bronze: 3},
|
||||
{country: "Canada", language: "English", name: "Mary", gold: 0, silver: 1, bronze: 3},
|
||||
{country: "Switzerland", language: "French", name: "Bob", gold: 2, silver: 3, bronze: 1},
|
||||
{country: "Switzerland", language: "French", name: "Jack", gold: 2, silver: 3, bronze: 1},
|
||||
{country: "Switzerland", language: "French", name: "Mary", gold: 1, silver: 3, bronze: 1},
|
||||
{country: "Switzerland", language: "French", name: "John", gold: 1, silver: 4, bronze: 1},
|
||||
{country: "Spain", language: "Spanish", name: "Bob", gold: 1, silver: 4, bronze: 0},
|
||||
{country: "Spain", language: "Spanish", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "Spain", language: "Spanish", name: "Sue", gold: 1, silver: 4, bronze: 1},
|
||||
{country: "Portugal", language: "Portuguese", name: "Mary", gold: 2, silver: 1, bronze: 4},
|
||||
{country: "Portugal", language: "Portuguese", name: "Tess", gold: 3, silver: 1, bronze: 1},
|
||||
{country: "Portugal", language: "Portuguese", name: "John", gold: 5, silver: 2, bronze: 1},
|
||||
{country: "Zimbabwe", language: "English", name: "Bob", gold: 3, silver: 1, bronze: 4},
|
||||
{country: "Zimbabwe", language: "English", name: "Jack", gold: 4, silver: 1, bronze: 4},
|
||||
{country: "Zimbabwe", language: "English", name: "Mary", gold: 2, silver: 1, bronze: 4},
|
||||
{country: "Brazil", language: "Brazillian", name: "Bob", gold: 3, silver: 4, bronze: 1},
|
||||
{country: "Brazil", language: "Brazillian", name: "Jack", gold: 2, silver: 4, bronze: 1},
|
||||
{country: "Brazil", language: "Brazillian", name: "Mary", gold: 4, silver: 0, bronze: 1},
|
||||
{country: "Brazil", language: "Brazillian", name: "John", gold: 1, silver: 0, bronze: 1}];
|
||||
}
|
||||
|
||||
render() {
|
||||
let divStyle = {
|
||||
height: 400,
|
||||
width: 900
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={divStyle} className="ag-fresh">
|
||||
<h1>Floating Filter Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
floatingFilter
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class SlidingFloatingFilter extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
maxValue: props.maxValue,
|
||||
currentValue: 0
|
||||
}
|
||||
}
|
||||
|
||||
valueChanged = (event) => {
|
||||
this.setState({
|
||||
currentValue: event.target.value
|
||||
},
|
||||
() => {
|
||||
this.props.onFloatingFilterChanged({model: this.buildModel()});
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
onParentModelChanged(parentModel) {
|
||||
// note that the filter could be anything here, but our purposes we're assuming a greater than filter only,
|
||||
// so just read off the value and use that
|
||||
this.setState({
|
||||
currentValue: !parentModel ? 0 : parentModel.filter
|
||||
});
|
||||
}
|
||||
|
||||
buildModel() {
|
||||
if (this.state.currentValue === 0) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
filterType: 'number',
|
||||
type: 'greaterThan',
|
||||
filter: this.state.currentValue,
|
||||
filterTo: null
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<input type="range"
|
||||
value={this.state.currentValue}
|
||||
min={0}
|
||||
max={this.state.maxValue}
|
||||
step={1}
|
||||
onChange={this.valueChanged}/>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import NameAndAgeRenderer from "./NameAndAgeRenderer";
|
||||
|
||||
export default class FullWidthComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {},
|
||||
|
||||
rowData: FullWidthComponentExample.createRowData(),
|
||||
columnDefs: FullWidthComponentExample.createColumnDefs()
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
isFullWidthCell(rowNode) {
|
||||
return (rowNode.id === "0") || (parseInt(rowNode.id) % 2 === 0);
|
||||
}
|
||||
|
||||
static createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Name",
|
||||
field: "name",
|
||||
width: 400
|
||||
},
|
||||
{
|
||||
headerName: "Age",
|
||||
field: "age",
|
||||
width: 399
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
static createRowData() {
|
||||
return [
|
||||
{name: "Bob", age: 10},
|
||||
{name: "Harry", age: 3},
|
||||
{name: "Sally", age: 20},
|
||||
{name: "Mary", age: 5},
|
||||
{name: "John", age: 15},
|
||||
{name: "Bob", age: 10},
|
||||
{name: "Harry", age: 3},
|
||||
{name: "Sally", age: 20},
|
||||
{name: "Mary", age: 5},
|
||||
{name: "John", age: 15},
|
||||
{name: "Jack", age: 25},
|
||||
{name: "Sue", age: 43},
|
||||
{name: "Sean", age: 44},
|
||||
{name: "Niall", age: 2},
|
||||
{name: "Alberto", age: 32},
|
||||
{name: "Fred", age: 53},
|
||||
{name: "Jenny", age: 34},
|
||||
{name: "Larry", age: 13},
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 900}}
|
||||
className="ag-fresh">
|
||||
<h1>Full Width Renderer Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
isFullWidthCell={this.isFullWidthCell}
|
||||
fullWidthCellRendererFramework={NameAndAgeRenderer}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class NameAndAgeRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.values = `Name: ${this.props.data.name}, Age: ${this.props.data.age}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
let style = {
|
||||
border: "2px solid #22ff22",
|
||||
borderRadius: "5px",
|
||||
backgroundColor: "#bbffbb"
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={style}>Full Width Column! { this.values }</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,126 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import MedalRenderer from "./MedalRenderer";
|
||||
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
export default class GroupedRowInnerRendererComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {},
|
||||
|
||||
rowData: this.createRowData(),
|
||||
columnDefs: this.createColumnDefs(),
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Country",
|
||||
field: "country",
|
||||
width: 100,
|
||||
rowGroupIndex: 0
|
||||
},
|
||||
{
|
||||
headerName: "Name",
|
||||
field: "name",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
headerName: "Gold",
|
||||
field: "gold",
|
||||
width: 100,
|
||||
aggFunc: 'sum'
|
||||
},
|
||||
{
|
||||
headerName: "Silver",
|
||||
field: "silver",
|
||||
width: 100,
|
||||
aggFunc: 'sum'
|
||||
},
|
||||
{
|
||||
headerName: "Bronze",
|
||||
field: "bronze",
|
||||
width: 100,
|
||||
aggFunc: 'sum'
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
return [
|
||||
{country: "United States", name: "Bob", gold: 1, silver: 0, bronze: 0},
|
||||
{country: "United States", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "United States", name: "Sue", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "United Kingdom", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "United Kingdom", name: "Tess", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "United Kingdom", name: "John", gold: 0, silver: 2, bronze: 1},
|
||||
{country: "Jamaica", name: "Bob", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Jamaica", name: "Jack", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Jamaica", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "South Africa", name: "Bob", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "South Africa", name: "Jack", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "South Africa", name: "Mary", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "South Africa", name: "John", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "New Zealand", name: "Bob", gold: 1, silver: 0, bronze: 0},
|
||||
{country: "New Zealand", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "New Zealand", name: "Sue", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Australia", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Australia", name: "Tess", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "Australia", name: "John", gold: 0, silver: 2, bronze: 1},
|
||||
{country: "Canada", name: "Bob", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Canada", name: "Jack", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Canada", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Switzerland", name: "Bob", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Switzerland", name: "Jack", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Switzerland", name: "Mary", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Switzerland", name: "John", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Spain", name: "Bob", gold: 1, silver: 0, bronze: 0},
|
||||
{country: "Spain", name: "Jack", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "Spain", name: "Sue", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Portugal", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Portugal", name: "Tess", gold: 0, silver: 1, bronze: 1},
|
||||
{country: "Portugal", name: "John", gold: 0, silver: 2, bronze: 1},
|
||||
{country: "Zimbabwe", name: "Bob", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Zimbabwe", name: "Jack", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Zimbabwe", name: "Mary", gold: 1, silver: 1, bronze: 0},
|
||||
{country: "Brazil", name: "Bob", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Brazil", name: "Jack", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Brazil", name: "Mary", gold: 1, silver: 0, bronze: 1},
|
||||
{country: "Brazil", name: "John", gold: 1, silver: 0, bronze: 1}
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 900}}
|
||||
className="ag-fresh">
|
||||
<h1>Group Row Renderer Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
groupUseEntireRow
|
||||
groupRowInnerRendererFramework={MedalRenderer}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class MedalRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.country = this.props.node.key;
|
||||
this.gold = this.props.node.aggData.gold;
|
||||
this.silver = this.props.node.aggData.silver;
|
||||
this.bronze = this.props.node.aggData.bronze;
|
||||
|
||||
// override the containing div so that the +/- and label are inline
|
||||
this.props.reactContainer.style.display = "inline-block";
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.country} Gold: {this.gold}, Silver: {this.silver}, Bronze: {this.bronze}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import StyledRenderer from "./StyledRenderer";
|
||||
|
||||
export default class PinnedRowComponentExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
gridOptions: {},
|
||||
|
||||
rowData: this.createRowData(),
|
||||
columnDefs: this.createColumnDefs(),
|
||||
|
||||
pinnedTopRowData: [{row: "Top Row", number: "Top Number"}],
|
||||
pinnedBottomRowData: [{row: "Bottom Row", number: "Bottom Number"}]
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Row",
|
||||
field: "row",
|
||||
width: 400,
|
||||
pinnedRowCellRendererFramework: StyledRenderer,
|
||||
pinnedRowCellRendererParams: {
|
||||
style: {'fontWeight': 'bold'}
|
||||
}
|
||||
},
|
||||
{
|
||||
headerName: "Number",
|
||||
field: "number",
|
||||
width: 399,
|
||||
pinnedRowCellRendererFramework: StyledRenderer,
|
||||
pinnedRowCellRendererParams: {
|
||||
style: {'fontStyle': 'italic'}
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
createRowData() {
|
||||
let rowData = [];
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
rowData.push({
|
||||
row: "Row " + i,
|
||||
number: Math.round(Math.random() * 100)
|
||||
});
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 900}}
|
||||
className="ag-fresh">
|
||||
<h1>Pinned Row Renderer Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
pinnedTopRowData={this.state.pinnedTopRowData}
|
||||
pinnedBottomRowData={this.state.pinnedBottomRowData}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class CurrencyRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span style={this.props.style}>{this.props.value}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class ClickableRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
cell: {
|
||||
row: this.props.value,
|
||||
col: this.props.colDef.headerName
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
clicked = () => {
|
||||
console.log("Child Cell Clicked: " + JSON.stringify(this.state.cell));
|
||||
};
|
||||
|
||||
render() {
|
||||
let buttonStyle = {
|
||||
lineHeight: 0.5,
|
||||
width: "98%"
|
||||
};
|
||||
return (
|
||||
<button style={buttonStyle} onClick={this.clicked} className="btn btn-info">Click Me</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class RatioRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let agRatioStyle = {
|
||||
display: "block",
|
||||
overflow: "hidden",
|
||||
border: "1px solid #ccc",
|
||||
borderRadius: "6px",
|
||||
background: "#fff",
|
||||
height: 20
|
||||
};
|
||||
|
||||
let svg = {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
pointerEvents: "none"
|
||||
};
|
||||
|
||||
let topBar = {
|
||||
fill: "#ff9933"
|
||||
};
|
||||
|
||||
let bottomBar = {
|
||||
fill: "#6699ff"
|
||||
};
|
||||
|
||||
return (
|
||||
<ag-ratio style={agRatioStyle}>
|
||||
<svg style={svg} viewBox="0 0 300 100" preserveAspectRatio="none">
|
||||
<rect x="0" y="0" width={this.props.value.top * 300} height="50" rx="4" ry="4" style={topBar}/>
|
||||
<rect x="0" y="50" width={this.props.value.bottom * 300} height="50" rx="4" ry="4" style={bottomBar}/>
|
||||
</svg>
|
||||
</ag-ratio>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import RatioRenderer from "./RatioRenderer";
|
||||
import ClickableRenderer from "./ClickableRenderer";
|
||||
|
||||
export default class RichComponentsExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
rowData: RichComponentsExample.createRowData(),
|
||||
columnDefs: RichComponentsExample.createColumnDefs()
|
||||
};
|
||||
}
|
||||
|
||||
onGridReady = (params) => {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
};
|
||||
|
||||
static createColumnDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: "Name",
|
||||
field: "name",
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
headerName: "Ratio Component",
|
||||
field: "ratios",
|
||||
cellRendererFramework: RatioRenderer,
|
||||
width: 350
|
||||
},
|
||||
{
|
||||
headerName: "Clickable Component",
|
||||
field: "name",
|
||||
cellRendererFramework: ClickableRenderer,
|
||||
width: 250
|
||||
}
|
||||
]; }
|
||||
|
||||
static createRowData() {
|
||||
return [
|
||||
{name: 'Homer Simpson', ratios: {top: 0.25, bottom: 0.75}},
|
||||
{name: 'Marge Simpson', ratios: {top: 0.67, bottom: 0.39}},
|
||||
{name: 'Bart Simpson', ratios: {top: 0.82, bottom: 0.47}},
|
||||
{name: 'Lisa Simpson', ratios: {top: 0.39, bottom: 1}},
|
||||
{name: 'Barney', ratios: {top: 0.22, bottom: 0.78}},
|
||||
{name: 'Sideshow Bob', ratios: {top: 0.13, bottom: 0.87}},
|
||||
{name: 'Ned Flanders', ratios: {top: 0.49, bottom: 0.51}},
|
||||
{name: 'Milhouse', ratios: {top: 0.69, bottom: 0.31}},
|
||||
{name: 'Apu', ratios: {top: 0.89, bottom: 0.11}},
|
||||
{name: 'Moe', ratios: {top: 0.64, bottom: 0.36}},
|
||||
{name: 'Smithers', ratios: {top: 0.09, bottom: 0.91}},
|
||||
{name: 'Edna Krabappel', ratios: {top: 0.39, bottom: 0.61}},
|
||||
{name: 'Krusty', ratios: {top: 0.74, bottom: 0.26}}
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 370, width: 900}} className="ag-fresh">
|
||||
<h1>Dynamic React Components - Richer Example</h1>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
gridOptions={this.state.gridOptions}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<h5>This example demonstrates Dynamic React Components with ag-Grid. Functionally similar
|
||||
to the <a href="/dynamic">Dynamic React Components Example</a> but with slightly richer components.</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">React Functionality</h4>
|
||||
<p className="card-text">Utilise React Components within ag-Grid</p>
|
||||
<a target="_blank" href="https://www.ag-grid.com/best-react-data-grid/?framework=react" className="btn btn-primary">React with ag-Grid</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-cell-rendering-components/?framework=react" className="btn btn-primary">React Renderers</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,124 +0,0 @@
|
||||
import SkillsCellRenderer from './SkillsCellRenderer.jsx';
|
||||
import NameCellEditor from './NameCellEditor.jsx';
|
||||
import ProficiencyCellRenderer from './ProficiencyCellRenderer.jsx';
|
||||
import RefData from './RefData';
|
||||
import SkillsFilter from './SkillsFilter.jsx';
|
||||
import ProficiencyFilter from './ProficiencyFilter.jsx';
|
||||
import HeaderGroupComponent from './HeaderGroupComponent.jsx';
|
||||
|
||||
export default class ColDefFactory {
|
||||
createColDefs() {
|
||||
return [
|
||||
{
|
||||
headerName: '#',
|
||||
width: 30,
|
||||
checkboxSelection: true,
|
||||
suppressSorting: true,
|
||||
suppressMenu: true,
|
||||
suppressFilter: true,
|
||||
pinned: true
|
||||
},
|
||||
{
|
||||
headerName: 'Employee',
|
||||
headerGroupComponentFramework: HeaderGroupComponent,
|
||||
children: [
|
||||
{
|
||||
headerName: "Name",
|
||||
field: "name",
|
||||
enableRowGroup: true,
|
||||
enablePivot: true,
|
||||
width: 150,
|
||||
pinned: true,
|
||||
editable: true,
|
||||
// use a React cellEditor
|
||||
cellEditorFramework: NameCellEditor
|
||||
},
|
||||
{
|
||||
headerName: "Country",
|
||||
field: "country",
|
||||
width: 150,
|
||||
enableRowGroup: true,
|
||||
enablePivot: true,
|
||||
// an example of using a non-React cell renderer
|
||||
cellRenderer: countryCellRenderer,
|
||||
pinned: true,
|
||||
filterParams: {
|
||||
cellRenderer: countryCellRenderer,
|
||||
cellHeight: 20
|
||||
}
|
||||
},
|
||||
{
|
||||
headerName: "DOB",
|
||||
field: "dob",
|
||||
width: 145,
|
||||
enableRowGroup: true,
|
||||
enablePivot: true,
|
||||
filter: 'date',
|
||||
pinned: true,
|
||||
cellRenderer: function (params) {
|
||||
return pad(params.value.getDate(), 2) + '/' +
|
||||
pad(params.value.getMonth() + 1, 2) + '/' +
|
||||
params.value.getFullYear();
|
||||
},
|
||||
columnGroupShow: 'open'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
headerName: 'IT Skills',
|
||||
children: [
|
||||
{
|
||||
headerName: "Skills",
|
||||
width: 125,
|
||||
suppressSorting: true,
|
||||
field: 'skills',
|
||||
enableRowGroup: true,
|
||||
enablePivot: true,
|
||||
// supply a React component
|
||||
cellRendererFramework: SkillsCellRenderer,
|
||||
// supply a React component
|
||||
filterFramework: SkillsFilter
|
||||
},
|
||||
{
|
||||
headerName: "Proficiency",
|
||||
field: "proficiency",
|
||||
width: 135,
|
||||
enableValue: true,
|
||||
// supply a React component
|
||||
cellRendererFramework: ProficiencyCellRenderer,
|
||||
// supply a React component
|
||||
filterFramework: ProficiencyFilter
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
headerName: 'Contact',
|
||||
children: [
|
||||
{headerName: "Mobile", field: "mobile", width: 150, filter: 'text'},
|
||||
{headerName: "Land-line", field: "landline", width: 150, filter: 'text'},
|
||||
{headerName: "Address", field: "address", width: 500, filter: 'text'}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// this is a simple cell renderer, putting together static html, no
|
||||
// need to use React for it.
|
||||
function countryCellRenderer(params) {
|
||||
if (params.value) {
|
||||
const flag = "<img border='0' width='15' height='10' " +
|
||||
"style='margin-bottom: 2px' src='http://flags.fmcdn.net/data/flags/mini/"
|
||||
+ RefData.COUNTRY_CODES[params.value] + ".png'>";
|
||||
return flag + " " + params.value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Utility function used to pad the date formatting.
|
||||
function pad(num, totalStringSize) {
|
||||
let asString = num + "";
|
||||
while (asString.length < totalStringSize) asString = "0" + asString;
|
||||
return asString;
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
import React from "react";
|
||||
import * as PropTypes from "prop-types";
|
||||
|
||||
// Date Component to be used in the date filter.
|
||||
// This is a very simple example of how a React component can be plugged as a DateComponentFramework
|
||||
// as you can see, the only requirement is that the React component implements the required methods
|
||||
// getDate and setDate and that it calls back into props.onDateChanged every time that the date changes.
|
||||
export default class DateComponent extends React.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: '2px'
|
||||
};
|
||||
let ddStyle = {
|
||||
width: '30px'
|
||||
};
|
||||
let mmStyle = {
|
||||
width: '30px'
|
||||
};
|
||||
let yyyyStyle = {
|
||||
width: '40px'
|
||||
};
|
||||
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"/>/
|
||||
<input onInput={this.onDateChanged.bind(this)} ref="mm" placeholder="mm" style={mmStyle}
|
||||
value={this.state.textBoxes.mm} maxLength="2"/>/
|
||||
<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;
|
||||
}
|
||||
}
|
||||
|
||||
// the grid will always pass in one props called 'params',
|
||||
// which is the grid passing you the params for the cellRenderer.
|
||||
// this piece is optional. the grid will always pass the 'params'
|
||||
// props, so little need for adding this validation meta-data.
|
||||
DateComponent.propTypes = {
|
||||
params: PropTypes.object
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
import React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
|
||||
// Header component to be used as default for all the columns.
|
||||
export default class HeaderGroupComponent extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.props.columnGroup.getOriginalColumnGroup().addEventListener('expandedChanged', this.onExpandChanged.bind(this));
|
||||
this.state = {
|
||||
expanded: null
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.onExpandChanged();
|
||||
}
|
||||
|
||||
render() {
|
||||
let arrowClassName = "customExpandButton " + (this.state.expanded ? " expanded" : " collapsed");
|
||||
|
||||
return <div>
|
||||
<div className="customHeaderLabel"> {this.props.displayName}</div>
|
||||
<div onClick={this.expandOrCollapse.bind(this)} className={arrowClassName}><i
|
||||
className="fa fa-arrow-right"/></div>
|
||||
</div>
|
||||
}
|
||||
|
||||
expandOrCollapse() {
|
||||
this.props.setExpanded(!this.state.expanded);
|
||||
};
|
||||
|
||||
onExpandChanged() {
|
||||
this.setState({
|
||||
expanded: this.props.columnGroup.getOriginalColumnGroup().isExpanded()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// the grid will always pass in one props called 'params',
|
||||
// which is the grid passing you the params for the cellRenderer.
|
||||
// this piece is optional. the grid will always pass the 'params'
|
||||
// props, so little need for adding this validation meta-data.
|
||||
HeaderGroupComponent.propTypes = {
|
||||
params: PropTypes.object
|
||||
};
|
||||
@@ -1,117 +0,0 @@
|
||||
import React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
|
||||
const KEY_BACKSPACE = 8;
|
||||
const KEY_DELETE = 46;
|
||||
const KEY_F2 = 113;
|
||||
|
||||
// cell renderer for the proficiency column. this is a very basic cell editor,
|
||||
export default class NameCellEditor extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// the entire ag-Grid properties are passed as one single object inside the params
|
||||
this.state = this.createInitialState(props);
|
||||
}
|
||||
|
||||
// work out how to present the data based on what the user hit. you don't need to do any of
|
||||
// this for your ag-Grid cellEditor to work, however it makes sense to do this so the user
|
||||
// experience is similar to Excel
|
||||
createInitialState(props) {
|
||||
|
||||
let startValue;
|
||||
const putCursorAtEndOnFocus = false;
|
||||
const highlightAllOnFocus = false;
|
||||
|
||||
if (props.keyPress === KEY_BACKSPACE || props.keyPress === KEY_DELETE) {
|
||||
// if backspace or delete pressed, we clear the cell
|
||||
startValue = '';
|
||||
} else if (props.charPress) {
|
||||
// if a letter was pressed, we start with the letter
|
||||
startValue = props.charPress;
|
||||
} else {
|
||||
// otherwise we start with the current value
|
||||
startValue = props.value;
|
||||
if (props.keyPress === KEY_F2) {
|
||||
this.putCursorAtEndOnFocus = true;
|
||||
} else {
|
||||
this.highlightAllOnFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value: startValue,
|
||||
putCursorAtEndOnFocus: putCursorAtEndOnFocus,
|
||||
highlightAllOnFocus: highlightAllOnFocus
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<input ref="textField" value={this.state.value} onChange={this.onChangeListener.bind(this)}/>
|
||||
);
|
||||
}
|
||||
|
||||
onChangeListener(event) {
|
||||
// if doing React, you will probably be using a library for managing immutable
|
||||
// objects better. to keep this example simple, we don't use one.
|
||||
const newState = {
|
||||
value: event.target.value,
|
||||
putCursorAtEndOnFocus: this.state.putCursorAtEndOnFocus,
|
||||
highlightAllOnFocus: this.state.highlightAllOnFocus
|
||||
};
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
// called by ag-Grid, to get the final value
|
||||
getValue() {
|
||||
return this.state.value;
|
||||
}
|
||||
|
||||
// cannot use componentDidMount because although the component might be ready from React's point of
|
||||
// view, it may not yet be in the browser (put in by ag-Grid) so focus will not work
|
||||
afterGuiAttached() {
|
||||
// get ref from React component
|
||||
const eInput = this.refs.textField;
|
||||
eInput.focus();
|
||||
if (this.highlightAllOnFocus) {
|
||||
eInput.select();
|
||||
} else {
|
||||
// when we started editing, we want the carot at the end, not the start.
|
||||
// this comes into play in two scenarios: a) when user hits F2 and b)
|
||||
// when user hits a printable character, then on IE (and only IE) the carot
|
||||
// was placed after the first character, thus 'apply' would end up as 'pplea'
|
||||
const length = eInput.value ? eInput.value.length : 0;
|
||||
if (length > 0) {
|
||||
eInput.setSelectionRange(length, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we want the editor to appear in a popup, then return true.
|
||||
isPopup() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return true here if you don't want to allow editing on the cell.
|
||||
isCancelBeforeStart() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// just to demonstrate, if you type in 'cancel' then the edit will not take effect
|
||||
isCancelAfterEnd() {
|
||||
if (this.state.value && this.state.value.toUpperCase() === 'CANCEL') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the grid will always pass in one props called 'params',
|
||||
// which is the grid passing you the params for the cellRenderer.
|
||||
// this piece is optional. the grid will always pass the 'params'
|
||||
// props, so little need for adding this validation meta-data.
|
||||
NameCellEditor.propTypes = {
|
||||
params: PropTypes.object
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// cell renderer for the proficiency column. this is a very basic cell renderer,
|
||||
// it is arguable that we should not of used React and just returned a string of
|
||||
// html as a normal ag-Grid cellRenderer.
|
||||
export default class ProficiencyCellRenderer extends React.Component {
|
||||
|
||||
render() {
|
||||
let backgroundColor;
|
||||
if (this.props.value < 20) {
|
||||
backgroundColor = 'red';
|
||||
} else if (this.props.value < 60) {
|
||||
backgroundColor = '#ff9900';
|
||||
} else {
|
||||
backgroundColor = '#00A000';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="div-percent-bar" style={{width: this.props.value + '%', backgroundColor: backgroundColor}}>
|
||||
<div className="div-percent-value">{this.props.value}%</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const PROFICIENCY_NAMES = ['No Filter', 'Above 40%', 'Above 60%', 'Above 80%'];
|
||||
|
||||
// the proficiency filter component. this demonstrates how to integrate
|
||||
// a React filter component with ag-Grid.
|
||||
export default class ProficiencyFilter extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selected: PROFICIENCY_NAMES[0]
|
||||
};
|
||||
}
|
||||
|
||||
// called by agGrid
|
||||
doesFilterPass(params) {
|
||||
const value = this.props.valueGetter(params);
|
||||
const valueAsNumber = parseFloat(value);
|
||||
|
||||
switch (this.state.selected) {
|
||||
case PROFICIENCY_NAMES[1] :
|
||||
return valueAsNumber >= 40;
|
||||
case PROFICIENCY_NAMES[2] :
|
||||
return valueAsNumber >= 60;
|
||||
case PROFICIENCY_NAMES[3] :
|
||||
return valueAsNumber >= 80;
|
||||
default :
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// called by agGrid
|
||||
isFilterActive() {
|
||||
return this.state.selected !== PROFICIENCY_NAMES[0];
|
||||
};
|
||||
|
||||
onButtonPressed(name) {
|
||||
const newState = {selected: name};
|
||||
// set the state, and once it is done, then call filterChangedCallback
|
||||
this.setState(newState, this.props.filterChangedCallback);
|
||||
}
|
||||
|
||||
|
||||
getModel() {
|
||||
return ''
|
||||
}
|
||||
|
||||
setModel(model) {
|
||||
}
|
||||
|
||||
render() {
|
||||
const rows = [];
|
||||
PROFICIENCY_NAMES.forEach((name) => {
|
||||
const selected = this.state.selected === name;
|
||||
rows.push(
|
||||
<div key={name}>
|
||||
<label style={{paddingLeft: 4}}>
|
||||
<input type="radio" checked={selected} name={Math.random()}
|
||||
onChange={this.onButtonPressed.bind(this, name)}/>
|
||||
{name}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{
|
||||
textAlign: 'center',
|
||||
background: 'lightgray',
|
||||
width: '100%',
|
||||
display: 'block',
|
||||
borderBottom: '1px solid grey'
|
||||
}}>
|
||||
<b>Custom Proficiency Filter</b>
|
||||
</div>
|
||||
{rows}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// these are other method that agGrid calls that we
|
||||
// could of implemented, but they are optional and
|
||||
// we have no use for them in this particular filter.
|
||||
//getApi() {}
|
||||
//afterGuiAttached(params) {}
|
||||
//onNewRowsLoaded() {}
|
||||
//onAnyFilterChanged() {}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
export default class RefData {
|
||||
}
|
||||
|
||||
RefData.FIRST_NAMES = [
|
||||
"Sophie", "Isabelle", "Emily", "Olivia", "Lily", "Chloe", "Isabella",
|
||||
"Amelia", "Jessica", "Sophia", "Ava", "Charlotte", "Mia", "Lucy", "Grace", "Ruby",
|
||||
"Ella", "Evie", "Freya", "Isla", "Poppy", "Daisy", "Layla"
|
||||
];
|
||||
|
||||
RefData.LAST_NAMES = [
|
||||
"Beckham", "Black", "Braxton", "Brennan", "Brock", "Bryson", "Cadwell",
|
||||
"Cage", "Carson", "Chandler", "Cohen", "Cole", "Corbin", "Dallas", "Dalton", "Dane",
|
||||
"Donovan", "Easton", "Fisher", "Fletcher", "Grady", "Greyson", "Griffin", "Gunner",
|
||||
"Hayden", "Hudson", "Hunter", "Jacoby", "Jagger", "Jaxon", "Jett", "Kade", "Kane",
|
||||
"Keating", "Keegan", "Kingston", "Kobe"
|
||||
];
|
||||
|
||||
RefData.COUNTRY_CODES = {
|
||||
Ireland: "ie",
|
||||
Spain: "es",
|
||||
"United Kingdom": "gb",
|
||||
France: "fr",
|
||||
Germany: "de",
|
||||
Sweden: "se",
|
||||
Italy: "it",
|
||||
Greece: "gr",
|
||||
Iceland: "is",
|
||||
Portugal: "pt",
|
||||
Malta: "mt",
|
||||
Norway: "no",
|
||||
Brazil: "br",
|
||||
Argentina: "ar",
|
||||
Colombia: "co",
|
||||
Peru: "pe",
|
||||
Venezuela: "ve",
|
||||
Uruguay: "uy"
|
||||
};
|
||||
|
||||
RefData.COUNTRIES = [
|
||||
{country: "Ireland", continent: "Europe", language: "English"},
|
||||
{country: "Spain", continent: "Europe", language: "Spanish"},
|
||||
{country: "United Kingdom", continent: "Europe", language: "English"},
|
||||
{country: "France", continent: "Europe", language: "French"},
|
||||
{country: "Germany", continent: "Europe", language: "(other)"},
|
||||
{country: "Sweden", continent: "Europe", language: "(other)"},
|
||||
{country: "Norway", continent: "Europe", language: "(other)"},
|
||||
{country: "Italy", continent: "Europe", language: "(other)"},
|
||||
{country: "Greece", continent: "Europe", language: "(other)"},
|
||||
{country: "Iceland", continent: "Europe", language: "(other)"},
|
||||
{country: "Portugal", continent: "Europe", language: "Portuguese"},
|
||||
{country: "Malta", continent: "Europe", language: "(other)"},
|
||||
{country: "Brazil", continent: "South America", language: "Portuguese"},
|
||||
{country: "Argentina", continent: "South America", language: "Spanish"},
|
||||
{country: "Colombia", continent: "South America", language: "Spanish"},
|
||||
{country: "Peru", continent: "South America", language: "Spanish"},
|
||||
{country: "Venezuela", continent: "South America", language: "Spanish"},
|
||||
{country: "Uruguay", continent: "South America", language: "Spanish"}
|
||||
];
|
||||
|
||||
RefData.DOB = [
|
||||
new Date(2000, 0, 1),
|
||||
new Date(2001, 1, 2),
|
||||
new Date(2002, 2, 3),
|
||||
new Date(2003, 3, 4),
|
||||
new Date(2004, 4, 5),
|
||||
new Date(2005, 5, 6),
|
||||
new Date(2006, 6, 7),
|
||||
new Date(2007, 7, 8),
|
||||
new Date(2008, 8, 9),
|
||||
new Date(2009, 9, 10),
|
||||
new Date(2010, 10, 11),
|
||||
new Date(2011, 11, 12)
|
||||
];
|
||||
|
||||
RefData.ADDRESSES = [
|
||||
'1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763',
|
||||
'3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215',
|
||||
'3235 High Forest, Glen Campbell, MS, 39035-6845, US, (601) 638-8186',
|
||||
'2234 Sleepy Pony Mall , Drain, DC, 20078-4243, US, (202) 948-3634',
|
||||
'2722 Hazy Turnabout, Burnt Cabins, NY, 14120-5642, US, (917) 604-6597',
|
||||
'6686 Lazy Ledge, Two Rock, CA, 92639-3020, US, (619) 901-9911',
|
||||
'2000 Dewy Limits, Wacahoota, NF, A4L-2V9, CA, (709) 065-3959',
|
||||
'7710 Noble Pond Avenue, Bolivia, RI, 02931-1842, US, (401) 865-2160',
|
||||
'3452 Sunny Vale, Pyro, ON, M8V-4Z0, CA, (519) 072-8609',
|
||||
'4402 Dusty Cove, Many Farms, UT, 84853-8223, US, (435) 518-0673',
|
||||
'5198 Silent Parade, Round Bottom, MD, 21542-9798, US, (301) 060-7245',
|
||||
'8550 Shady Moor, Kitty Fork, CO, 80941-6207, US, (303) 502-3767',
|
||||
'2131 Old Dell, Merry Midnight, AK, 99906-8842, US, (907) 369-2206',
|
||||
'7390 Harvest Crest, Mosquito Crossing, RI, 02957-6116, US, (401) 463-6348',
|
||||
'874 Little Point, Hot Coffee, BC, V3U-2P6, CA, (250) 706-9207',
|
||||
'8834 Stony Pioneer Heights, Newlove, OR, 97419-8670, US, (541) 408-2213',
|
||||
'9829 Grand Beach, Flint, UT, 84965-9900, US, (435) 700-5161',
|
||||
'3799 Cozy Blossom Ramp, Ptarmigan, MS, 38715-0313, US, (769) 740-1526',
|
||||
'3254 Silver Island Loop, Maunaloa, DE, 19869-3169, US, (302) 667-7671',
|
||||
'1081 Middle Wood, Taylors Gut Landing, OR, 97266-2873, US, (541) 357-6310',
|
||||
'1137 Umber Trail, Shacktown, NW, X3U-5Y8, CA, (867) 702-6883',
|
||||
'9914 Hidden Bank, Wyoming, MO, 64635-9665, US, (636) 280-4192',
|
||||
'7080 Misty Nectar Townline, Coward, AB, T9U-3N4, CA, (403) 623-2838',
|
||||
'1184 Wishing Grounds, Vibank, NW, X7D-0V9, CA, (867) 531-2730',
|
||||
'126 Easy Pointe, Grandview Beach, KY, 40928-9539, US, (502) 548-0956',
|
||||
'6683 Colonial Street, Swan River, BC, V1A-9I8, CA, (778) 014-4257',
|
||||
'960 Gentle Oak Lane, Shakopee, ND, 58618-6277, US, (701) 327-1219',
|
||||
'6918 Cotton Pine Corner, Kenaston, IA, 52165-3975, US, (515) 906-7427',
|
||||
'2368 Burning Woods, Ernfold, NY, 11879-9186, US, (646) 819-0355',
|
||||
'5646 Quiet Shadow Chase, Tiger Tail, IA, 52283-5537, US, (712) 375-9225',
|
||||
'5466 Foggy Mountain Dale, Sweet Home, MT, 59738-0251, US, (406) 881-1706',
|
||||
'5313 Clear Willow Route, Amazon, BC, V0S-2S6, CA, (604) 340-7596',
|
||||
'7000 Pleasant Autoroute, Spaceport City, UT, 84749-2448, US, (435) 154-3360',
|
||||
'8359 Quaking Anchor Road, Gross, BC, V9O-0H5, CA, (250) 985-3859',
|
||||
'5143 Amber Deer Hollow, New Deal, ND, 58446-0853, US, (701) 927-0322',
|
||||
'6230 Jagged Bear Key, Young, AR, 72337-3811, US, (501) 805-7239',
|
||||
'7207 Heather Vista, Devon, WY, 82520-1771, US, (307) 358-7092',
|
||||
'9416 Red Rise Place, Spraytown, OK, 73809-4766, US, (580) 867-1973',
|
||||
'3770 Golden Horse Diversion, Yelland, IL, 60471-1487, US, (224) 717-9349',
|
||||
'4819 Honey Treasure Park, Alaska, NB, E1U-3I0, CA, (506) 656-9138',
|
||||
'6187 Round Front, Land O Lakes, AK, 99873-6403, US, (907) 853-9063',
|
||||
'9218 Crystal Highway, Pickelville, MT, 59847-9299, US, (406) 076-0024',
|
||||
'6737 Bright Quay, Lazy Mountain, KY, 42390-4772, US, (606) 256-7288',
|
||||
'237 Merry Campus, Twentysix, SC, 29330-4909, US, (864) 945-0157',
|
||||
'446 Fallen Gate Rise, Petrolia, SC, 29959-9527, US, (864) 826-0553',
|
||||
'2347 Indian Boulevard, Frisbee, VA, 23797-6458, US, (703) 656-8445',
|
||||
'365 Emerald Grove Line, Level, NC, 28381-1514, US, (919) 976-7958',
|
||||
'1207 Iron Extension, Klickitat, SC, 29197-8571, US, (803) 535-7888',
|
||||
'6770 Cinder Glen, Caronport, OH, 45053-5002, US, (440) 369-4018',
|
||||
'7619 Tawny Carrefour, Senlac, NV, 89529-9876, US, (775) 901-6433'];
|
||||
|
||||
RefData.IT_SKILLS = ['android', 'css', 'html5', 'mac', 'windows'];
|
||||
|
||||
RefData.IT_SKILLS_NAMES = ['Android', 'CSS', 'HTML 5', 'Mac', 'Windows'];
|
||||
@@ -1,27 +0,0 @@
|
||||
.ag-cell {
|
||||
padding-top: 2px !important;
|
||||
padding-bottom: 2px !important;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
.div-percent-bar {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.div-percent-value {
|
||||
position: absolute;
|
||||
padding-left: 4px;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.div-outer-div {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,316 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import RowDataFactory from "./RowDataFactory";
|
||||
import ColDefFactory from "./ColDefFactory.jsx";
|
||||
import DateComponent from "./DateComponent.jsx";
|
||||
import SortableHeaderComponent from "./SortableHeaderComponent";
|
||||
|
||||
import "./RichGridExample.css";
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
export default class RichGridExample extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
quickFilterText: null,
|
||||
showToolPanel: false,
|
||||
columnDefs: new ColDefFactory().createColDefs(),
|
||||
rowData: new RowDataFactory().createRowData(),
|
||||
icons: {
|
||||
columnRemoveFromGroup: '<i class="fa fa-remove"/>',
|
||||
filter: '<i class="fa fa-filter"/>',
|
||||
sortAscending: '<i class="fa fa-long-arrow-down"/>',
|
||||
sortDescending: '<i class="fa fa-long-arrow-up"/>',
|
||||
groupExpanded: '<i class="fa fa-minus-square-o"/>',
|
||||
groupContracted: '<i class="fa fa-plus-square-o"/>',
|
||||
columnGroupOpened: '<i class="fa fa-minus-square-o"/>',
|
||||
columnGroupClosed: '<i class="fa fa-plus-square-o"/>'
|
||||
}
|
||||
};
|
||||
|
||||
// the grid options are optional, because you can provide every property
|
||||
// to the grid via standard React properties. however, the react interface
|
||||
// doesn't block you from using the standard JavaScript interface if you
|
||||
// wish. Maybe you have the gridOptions stored as JSON on your server? If
|
||||
// you do, the providing the gridOptions as a standalone object is just
|
||||
// what you want!
|
||||
this.gridOptions = {
|
||||
//We register the react date component that ag-grid will use to render
|
||||
dateComponentFramework: DateComponent,
|
||||
// this is how you listen for events using gridOptions
|
||||
onModelUpdated: function () {
|
||||
console.log('event onModelUpdated received');
|
||||
},
|
||||
defaultColDef: {
|
||||
headerComponentFramework: SortableHeaderComponent,
|
||||
headerComponentParams: {
|
||||
menuIcon: 'fa-bars'
|
||||
}
|
||||
},
|
||||
// this is a simple property
|
||||
rowBuffer: 10, // no need to set this, the default is fine for almost all scenarios,
|
||||
floatingFilter: true
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* Grid Events we're listening to */
|
||||
onGridReady = (params) => {
|
||||
this.api = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
};
|
||||
|
||||
onCellClicked = (event) => {
|
||||
console.log('onCellClicked: ' + event.data.name + ', col ' + event.colIndex);
|
||||
};
|
||||
|
||||
onRowSelected = (event) => {
|
||||
console.log('onRowSelected: ' + event.node.data.name);
|
||||
};
|
||||
|
||||
/* Demo related methods */
|
||||
onToggleToolPanel = (event) => {
|
||||
this.setState({showToolPanel: event.target.checked});
|
||||
};
|
||||
|
||||
deselectAll() {
|
||||
this.api.deselectAll();
|
||||
}
|
||||
|
||||
onQuickFilterText = (event) => {
|
||||
this.setState({quickFilterText: event.target.value});
|
||||
};
|
||||
|
||||
onRefreshData = () => {
|
||||
this.setState({
|
||||
rowData: new RowDataFactory().createRowData()
|
||||
});
|
||||
};
|
||||
|
||||
invokeSkillsFilterMethod = () => {
|
||||
let skillsFilter = this.api.getFilterInstance('skills');
|
||||
let componentInstance = skillsFilter.getFrameworkComponentInstance();
|
||||
componentInstance.helloFromSkillsFilter();
|
||||
};
|
||||
|
||||
dobFilter = () => {
|
||||
let dateFilterComponent = this.api.getFilterInstance('dob');
|
||||
dateFilterComponent.setFilterType('equals');
|
||||
dateFilterComponent.setDateFrom('2000-01-01');
|
||||
|
||||
// as the date filter is a React component, and its using setState internally, we need
|
||||
// to allow time for the state to be set (as setState is an async operation)
|
||||
// simply wait for the next tick
|
||||
setTimeout(() => {
|
||||
this.api.onFilterChanged();
|
||||
}, 0)
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{width: '900px'}}>
|
||||
<h1>Rich Grid with Declarative Markup Example</h1>
|
||||
<div style={{display: "inline-block", width: "100%"}}>
|
||||
<div style={{float: "left"}}>
|
||||
<b>Employees Skills and Contact Details</b><span id="rowCount"/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{marginTop: 10}}>
|
||||
<div>
|
||||
<span>
|
||||
Grid API:
|
||||
<button onClick={() => { this.api.selectAll() }} className="btn btn-primary">Select All</button>
|
||||
<button onClick={() => { this.api.deselectAll() }} className="btn btn-primary">Clear Selection</button>
|
||||
</span>
|
||||
<span style={{float: "right"}}>
|
||||
Column API:
|
||||
<button onClick={() => { this.columnApi.setColumnVisible('country', false) }} className="btn btn-primary">Hide Country Column</button>
|
||||
<button onClick={() => { this.columnApi.setColumnVisible('country', true) }} className="btn btn-primary">Show Country Column</button>
|
||||
</span>
|
||||
</div>
|
||||
<div style={{display: "inline-block", width: "100%", marginTop: 10, marginBottom: 10}}>
|
||||
<div style={{float: "left"}}>
|
||||
<label>
|
||||
<input type="checkbox" onChange={this.onToggleToolPanel} style={{marginRight: 5}}/>
|
||||
Show Tool Panel
|
||||
</label>
|
||||
</div>
|
||||
<div style={{float: "left", marginLeft: 20}}>
|
||||
<button onClick={this.onRefreshData} className="btn btn-primary">Refresh Data</button>
|
||||
</div>
|
||||
<div style={{float: "left", marginLeft: 20}}>
|
||||
<input type="text" onChange={this.onQuickFilterText} placeholder="Type text to filter..."/>
|
||||
</div>
|
||||
<div style={{float: "right"}}>
|
||||
Filter API:
|
||||
<button onClick={this.invokeSkillsFilterMethod}
|
||||
className="btn btn-primary">Invoke Skills Filter Method
|
||||
</button>
|
||||
<button onClick={this.dobFilter} className="btn btn-primary">DOB equals to 01/01/2000ß</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{height: 400, width: 900}} className="ag-fresh">
|
||||
<AgGridReact
|
||||
ref="myGrid"
|
||||
// gridOptions is optional - it's possible to provide
|
||||
// all values as React props
|
||||
gridOptions={this.gridOptions}
|
||||
|
||||
// listening for events
|
||||
onGridReady={this.onGridReady}
|
||||
onRowSelected={this.onRowSelected}
|
||||
onCellClicked={this.onCellClicked}
|
||||
|
||||
// binding to simple properties
|
||||
showToolPanel={this.state.showToolPanel}
|
||||
quickFilterText={this.state.quickFilterText}
|
||||
|
||||
// binding to an object property
|
||||
icons={this.state.icons}
|
||||
|
||||
// binding to array properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
|
||||
// no binding, just providing hard coded strings for the properties
|
||||
// boolean properties will default to true if provided (ie enableColResize => enableColResize="true")
|
||||
suppressRowClickSelection
|
||||
rowSelection="multiple"
|
||||
enableColResize
|
||||
enableSorting
|
||||
enableFilter
|
||||
groupHeaders
|
||||
rowHeight="22"/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="row">
|
||||
<div className="col-sm-12"><h1>Rich Grid Example</h1></div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<h5>This example demonstrates many features of ag-Grid.</h5>
|
||||
<p><span style={{fontWeight: 500}}>Select All/Clear Selection</span>: Select or Deselect
|
||||
All
|
||||
Rows</p>
|
||||
<p><span style={{fontWeight: 500}}>Hide/Show Country Column</span>: Select or Deselect
|
||||
All
|
||||
Rows
|
||||
(expand the Employee column to show the Country column first)</p>
|
||||
<p><span style={{fontWeight: 500}}>Toggle The Tool Panel</span>: Let your users Pivot,
|
||||
Group
|
||||
and
|
||||
Aggregate using the Tool Panel</p>
|
||||
<p><span style={{fontWeight: 500}}>Refresh Data</span>: Dynamically Update Grid Data</p>
|
||||
<p><span style={{fontWeight: 500}}>Quick Filter</span>: Perform Quick Grid Wide
|
||||
Filtering
|
||||
with
|
||||
the Quick Filter</p>
|
||||
<p><span style={{fontWeight: 500}}>DOB Filter</span>: Set the DOB filter to 01/01/2000
|
||||
using
|
||||
the
|
||||
Filter API (expand the Employee column to show the DOB column)</p>
|
||||
<p><span style={{fontWeight: 500}}>Custom Headers</span>: Sort, Filter and Render
|
||||
Headers
|
||||
using
|
||||
Header Components</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-4">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">Grid & Column API</h4>
|
||||
<p className="card-text">Utilise Grid Features Programmatically Using the APIs
|
||||
Available</p>
|
||||
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-api/"
|
||||
className="btn btn-primary">Grid API</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-column-api/"
|
||||
className="btn btn-primary">Column API</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">Header Components</h4>
|
||||
<p className="card-text">Customer the Header with React Components</p>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com//javascript-grid-header-rendering/#headerComponent"
|
||||
className="btn btn-primary">Header Component</a>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com//javascript-grid-header-rendering/#headerGroupComponent"
|
||||
className="btn btn-primary">Header Group Component</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">Filters</h4>
|
||||
<p className="card-text">Filter with Quick Filters, Floating Filters, Built In
|
||||
Filters
|
||||
or Using the
|
||||
Filter API</p>
|
||||
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-filter-quick/"
|
||||
className="btn btn-primary">Quick
|
||||
Filter</a>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com//javascript-grid-floating-filter-component/"
|
||||
className="btn btn-primary">Floating Filters</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-filtering/"
|
||||
className="btn btn-primary">Built in
|
||||
Filters</a>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com//javascript-grid-filtering/#accessing-filter-component-instances"
|
||||
className="btn btn-primary">Filter API</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-4">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">Tool Panel</h4>
|
||||
<p className="card-text">Let your users Pivot, Group and Aggregate using the
|
||||
Tool
|
||||
Panel</p>
|
||||
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-tool-panel/"
|
||||
className="btn btn-primary">Tool Panel</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-8">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h4 className="card-title">The Rest</h4>
|
||||
<p className="card-text">Pinned Columns, Checkbox Selection, Customer Renderers,
|
||||
Data
|
||||
Updates</p>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com/best-react-data-grid/?framework=react"
|
||||
className="btn btn-primary">React with ag-Grid</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com//javascript-grid-pinning/"
|
||||
className="btn btn-primary">Pinned Column</a>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com//javascript-grid-selection/#checkboxSelection"
|
||||
className="btn btn-primary">Checkbox Selection</a>
|
||||
<a target="_blank"
|
||||
href="https://www.ag-grid.com//javascript-grid-cell-rendering/"
|
||||
className="btn btn-primary">Cell
|
||||
Renderers</a>
|
||||
<a target="_blank" href="https://www.ag-grid.com/javascript-grid-data-update/"
|
||||
className="btn btn-primary">Updating Data</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import RefData from './RefData';
|
||||
|
||||
export default class RowDataFactory {
|
||||
|
||||
createRowData() {
|
||||
const rowData = [];
|
||||
|
||||
for (let i = 0; i < 200; i++) {
|
||||
const countryData = RefData.COUNTRIES[i % RefData.COUNTRIES.length];
|
||||
rowData.push({
|
||||
name: RefData.FIRST_NAMES[i % RefData.FIRST_NAMES.length] + ' ' + RefData.LAST_NAMES[i % RefData.LAST_NAMES.length],
|
||||
skills: {
|
||||
android: Math.random() < 0.4,
|
||||
html5: Math.random() < 0.4,
|
||||
mac: Math.random() < 0.4,
|
||||
windows: Math.random() < 0.4,
|
||||
css: Math.random() < 0.4
|
||||
},
|
||||
dob: RefData.DOB[i % RefData.DOB.length],
|
||||
address: RefData.ADDRESSES[i % RefData.ADDRESSES.length],
|
||||
years: Math.round(Math.random() * 100),
|
||||
proficiency: Math.round(Math.random() * 100),
|
||||
country: countryData.country,
|
||||
continent: countryData.continent,
|
||||
language: countryData.language,
|
||||
mobile: this.createRandomPhoneNumber(),
|
||||
landline: this.createRandomPhoneNumber()
|
||||
});
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
|
||||
createRandomPhoneNumber() {
|
||||
let result = '+';
|
||||
for (let i = 0; i < 12; i++) {
|
||||
result += Math.round(Math.random() * 10);
|
||||
if (i === 2 || i === 5 || i === 8) {
|
||||
result += ' ';
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import RefData from './RefData';
|
||||
|
||||
export default class SkillsCellRenderer extends React.Component {
|
||||
|
||||
render() {
|
||||
const skills = [];
|
||||
const rowData = this.props.data;
|
||||
RefData.IT_SKILLS.forEach((skill) => {
|
||||
if (rowData && rowData.skills && rowData.skills[skill]) {
|
||||
skills.push(<img key={skill} src={'images/skills/' + skill + '.png'} width={16} title={skill}/>);
|
||||
}
|
||||
});
|
||||
|
||||
return <span>{skills}</span>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// the grid will always pass in one props called 'params',
|
||||
// which is the grid passing you the params for the cellRenderer.
|
||||
// this piece is optional. the grid will always pass the 'params'
|
||||
// props, so little need for adding this validation meta-data.
|
||||
SkillsCellRenderer.propTypes = {
|
||||
params: PropTypes.object
|
||||
};
|
||||
@@ -1,126 +0,0 @@
|
||||
import React from 'react';
|
||||
import RefData from './RefData';
|
||||
|
||||
// the skills filter component. this can be laid out much better in a 'React'
|
||||
// way. there are design patterns you can apply to layout out your React classes.
|
||||
// however, i'm not worried, as the intention here is to show you ag-Grid
|
||||
// working with React, and that's all. i'm not looking for any awards for my
|
||||
// React design skills.
|
||||
export default class SkillsFilter extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
android: false,
|
||||
css: false,
|
||||
html5: false,
|
||||
mac: false,
|
||||
windows: false
|
||||
};
|
||||
}
|
||||
|
||||
getModel() {
|
||||
return {
|
||||
android: this.state.android,
|
||||
css: this.state.css,
|
||||
html5: this.state.html5,
|
||||
mac: this.state.mac,
|
||||
windows: this.state.windows
|
||||
}
|
||||
}
|
||||
|
||||
setModel(model) {
|
||||
this.setState({
|
||||
android: model ? model.android : null,
|
||||
css: model ? model.css : null,
|
||||
html5: model ? model.html5 : null,
|
||||
mac: model ? model.mac : null,
|
||||
windows: model ? model.windows : null
|
||||
});
|
||||
}
|
||||
|
||||
// called by agGrid
|
||||
doesFilterPass(params) {
|
||||
|
||||
const rowSkills = params.data.skills;
|
||||
let passed = true;
|
||||
|
||||
RefData.IT_SKILLS.forEach((skill) => {
|
||||
if (this.state[skill]) {
|
||||
if (!rowSkills[skill]) {
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return passed;
|
||||
};
|
||||
|
||||
getModel() {
|
||||
return ''
|
||||
}
|
||||
|
||||
// called by agGrid
|
||||
isFilterActive() {
|
||||
const somethingSelected = this.state.android || this.state.css ||
|
||||
this.state.html5 || this.state.mac || this.state.windows;
|
||||
return somethingSelected;
|
||||
};
|
||||
|
||||
onSkillChanged(skill, event) {
|
||||
const newValue = event.target.checked;
|
||||
const newModel = {};
|
||||
newModel[skill] = newValue;
|
||||
// set the state, and once it is done, then call filterChangedCallback
|
||||
this.setState(newModel, this.props.filterChangedCallback);
|
||||
}
|
||||
|
||||
helloFromSkillsFilter() {
|
||||
alert("Hello From The Skills Filter!");
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const skillsTemplates = [];
|
||||
RefData.IT_SKILLS.forEach((skill, index) => {
|
||||
|
||||
const skillName = RefData.IT_SKILLS_NAMES[index];
|
||||
const template = (
|
||||
<label key={skill}
|
||||
style={{border: '1px solid lightgrey', margin: 4, padding: 4, display: 'inline-block'}}>
|
||||
<span>
|
||||
<div style={{textAlign: 'center'}}>{skillName}</div>
|
||||
<div>
|
||||
<input type="checkbox" onClick={this.onSkillChanged.bind(this, skill)}/>
|
||||
<img src={'images/skills/' + skill + '.png'} width={30}/>
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
|
||||
skillsTemplates.push(template);
|
||||
});
|
||||
|
||||
return (
|
||||
<div style={{width: 380}}>
|
||||
<div style={{
|
||||
textAlign: 'center',
|
||||
background: 'lightgray',
|
||||
width: '100%',
|
||||
display: 'block',
|
||||
borderBottom: '1px solid grey'
|
||||
}}>
|
||||
<b>Custom Skills Filter</b>
|
||||
</div>
|
||||
{skillsTemplates}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// these are other method that agGrid calls that we
|
||||
// could of implemented, but they are optional and
|
||||
// we have no use for them in this particular filter.
|
||||
//afterGuiAttached(params) {}
|
||||
//onNewRowsLoaded() {}
|
||||
//onAnyFilterChanged() {}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import React from "react";
|
||||
import * as PropTypes from "prop-types";
|
||||
|
||||
// Header component to be used as default for all the columns.
|
||||
export default class SortableHeaderComponent extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// this.sortChanged = this.onSortChanged.bind(this);
|
||||
this.props.column.addEventListener('sortChanged', this.onSortChanged);
|
||||
|
||||
//The state of this component contains the current sort state of this column
|
||||
//The possible values are: 'asc', 'desc' and ''
|
||||
this.state = {
|
||||
sorted: ''
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.column.removeEventListener('sortChanged', this.onSortChanged);
|
||||
}
|
||||
|
||||
render() {
|
||||
let sortElements = [];
|
||||
if (this.props.enableSorting) {
|
||||
let downArrowClass = "customSortDownLabel " + (this.state.sorted === 'desc' ? " active" : "");
|
||||
let upArrowClass = "customSortUpLabel " + (this.state.sorted === 'asc' ? " active" : "");
|
||||
let removeArrowClass = "customSortRemoveLabel " + (this.state.sorted === '' ? " active" : "");
|
||||
|
||||
sortElements.push(<div key={`up${this.props.displayName}`} className={downArrowClass}
|
||||
onClick={this.onSortRequested.bind(this, 'desc')}><i
|
||||
className="fa fa-long-arrow-down"/></div>);
|
||||
sortElements.push(<div key={`down${this.props.displayName}`} className={upArrowClass}
|
||||
onClick={this.onSortRequested.bind(this, 'asc')}><i
|
||||
className="fa fa-long-arrow-up"/></div>);
|
||||
sortElements.push(<div key={`minus${this.props.displayName}`} className={removeArrowClass}
|
||||
onClick={this.onSortRequested.bind(this, '')}><i
|
||||
className="fa fa-times"/></div>)
|
||||
}
|
||||
|
||||
|
||||
let menuButton = null;
|
||||
if (this.props.enableMenu) {
|
||||
menuButton =
|
||||
<div ref="menuButton" className="customHeaderMenuButton" onClick={this.onMenuClick.bind(this)}><i
|
||||
className={"fa " + this.props.menuIcon}/></div>
|
||||
}
|
||||
|
||||
return <div>
|
||||
{menuButton}
|
||||
<div className="customHeaderLabel">{this.props.displayName}</div>
|
||||
{sortElements}
|
||||
</div>
|
||||
}
|
||||
|
||||
onSortRequested(order, event) {
|
||||
this.props.setSort(order, event.shiftKey);
|
||||
};
|
||||
|
||||
onSortChanged = () => {
|
||||
if (this.props.column.isSortAscending()) {
|
||||
this.setState({
|
||||
sorted: 'asc'
|
||||
})
|
||||
} else if (this.props.column.isSortDescending()) {
|
||||
this.setState({
|
||||
sorted: 'desc'
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
sorted: ''
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
onMenuClick() {
|
||||
this.props.showColumnMenu(this.refs.menuButton);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// the grid will always pass in one props called 'params',
|
||||
// which is the grid passing you the params for the cellRenderer.
|
||||
// this piece is optional. the grid will always pass the 'params'
|
||||
// props, so little need for adding this validation meta-data.
|
||||
SortableHeaderComponent.propTypes = {
|
||||
params: PropTypes.object
|
||||
};
|
||||
@@ -1,102 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
import {AgGridReact} from "ag-grid-react";
|
||||
import {connect} from "react-redux";
|
||||
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
import {updateRowSelection} from "./gridDataActions";
|
||||
|
||||
/*
|
||||
* This component serves to display the row data (provided by redux)
|
||||
*/
|
||||
class GridComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
columnDefs: [
|
||||
{headerName: 'Symbol', field: 'symbol'},
|
||||
{headerName: 'Price', field: 'price'},
|
||||
{headerName: 'Group', field: 'group'}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
onGridReady = (params) => {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
|
||||
// set the initial group state
|
||||
this.setGroupingEnabled(false);
|
||||
};
|
||||
|
||||
// on selection publish selected row ids
|
||||
onSelectionChanged = () => {
|
||||
let selectedRowNodes = this.gridApi.getSelectedNodes();
|
||||
let selectedIds = selectedRowNodes.map((rowNode) => rowNode.id);
|
||||
|
||||
this.props.dispatch(updateRowSelection(selectedIds));
|
||||
};
|
||||
|
||||
setGroupingEnabled = (enabled) => {
|
||||
if (enabled) {
|
||||
this.columnApi.addRowGroupColumn('group');
|
||||
this.columnApi.setColumnVisible('group', false);
|
||||
this.columnApi.setColumnVisible('symbol', false);
|
||||
} else {
|
||||
this.columnApi.removeRowGroupColumn('group');
|
||||
this.columnApi.setColumnVisible('group', true);
|
||||
this.columnApi.setColumnVisible('symbol', true);
|
||||
}
|
||||
};
|
||||
|
||||
// row data will be provided via redux on this.props.rowData
|
||||
// we bind to this and using "deltaRowDataMode" the grid will only re-render rows that have changed
|
||||
// this requires each row to have a uniquely identifying property - in this case the row data "symbol" (see getRowNodeId)
|
||||
render() {
|
||||
return (
|
||||
<div style={{height: 400, width: 900, marginTop: 15}}
|
||||
className="ag-fresh">
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.props.rowData}
|
||||
|
||||
deltaRowDataMode
|
||||
suppressCellSelection
|
||||
animateRows
|
||||
enableColResize
|
||||
rowSelection="multiple"
|
||||
autoColumnGroupDef={{
|
||||
headerName: 'Symbol',
|
||||
cellRenderer: 'group',
|
||||
field: 'symbol'
|
||||
}}
|
||||
groupDefaultExpanded="1"
|
||||
enableSorting
|
||||
getRowNodeId={(data) => data.symbol}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}
|
||||
onSelectionChanged={this.onSelectionChanged}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// pull off row data changes
|
||||
export default connect(
|
||||
(state) => {
|
||||
return {
|
||||
rowData: state.rowData
|
||||
}
|
||||
},
|
||||
null,
|
||||
null,
|
||||
{withRef: true}
|
||||
)(GridComponent);
|
||||
@@ -1,175 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
import {connect} from "react-redux";
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
import {updateRowData} from "./gridDataActions";
|
||||
|
||||
/*
|
||||
* This component serves both to host the demo controls, which in turn will drive row data state changes
|
||||
*/
|
||||
class HeaderComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
groupingOn: false
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// provide the initial data to the store (which in turn will populate the grid)
|
||||
this.props.dispatch(updateRowData(this.createRowData()));
|
||||
}
|
||||
|
||||
// add five new items to the row data and publish the change
|
||||
addFiveItems = () => {
|
||||
let newRowData = this.props.rowData.slice();
|
||||
for (let i = 0; i < 5; i++) {
|
||||
let newItem = this.createItem();
|
||||
newRowData.push(newItem);
|
||||
}
|
||||
|
||||
this.props.dispatch(updateRowData(newRowData));
|
||||
};
|
||||
|
||||
|
||||
// remove selected rows from the data set and publish the change
|
||||
removeSelected = () => {
|
||||
let newRowData = this.props.rowData.filter((dataItem) => (this.props.rowSelection.indexOf(dataItem.symbol) < 0));
|
||||
this.props.dispatch(updateRowData(newRowData));
|
||||
};
|
||||
|
||||
// group data based on selection and publish the change
|
||||
setSelectedToGroup = (newGroup) => {
|
||||
let selectedIds = this.props.rowSelection;
|
||||
let newRowData = this.props.rowData.map((dataItem) => {
|
||||
let itemSelected = selectedIds.indexOf(dataItem.symbol) >= 0;
|
||||
if (itemSelected) {
|
||||
return {
|
||||
// symbol and price stay the same
|
||||
symbol: dataItem.symbol,
|
||||
price: dataItem.price,
|
||||
// group gets the group
|
||||
group: newGroup
|
||||
};
|
||||
} else {
|
||||
return dataItem;
|
||||
}
|
||||
});
|
||||
|
||||
this.props.dispatch(updateRowData(newRowData));
|
||||
};
|
||||
|
||||
// randomly update prices in the row data and publish the change
|
||||
updatePrices = () => {
|
||||
let newRowData = [];
|
||||
this.props.rowData.forEach(function (item) {
|
||||
newRowData.push({
|
||||
// use same symbol as last time, this is the unique id
|
||||
symbol: item.symbol,
|
||||
// group also stays the same
|
||||
group: item.group,
|
||||
// add random price
|
||||
price: Math.floor(Math.random() * 100)
|
||||
});
|
||||
});
|
||||
|
||||
this.props.dispatch(updateRowData(newRowData));
|
||||
};
|
||||
|
||||
setGroupingEnabled = (enabled) => {
|
||||
this.setState({
|
||||
groupingOn: enabled
|
||||
});
|
||||
|
||||
// let the parent (and the grid in turn) know about the grouping state change
|
||||
this.props.setGroupingEnabled(enabled);
|
||||
|
||||
// toggle the grouping buttons visibility
|
||||
this.setItemVisible('groupingOn', !enabled);
|
||||
this.setItemVisible('groupingOff', enabled);
|
||||
};
|
||||
|
||||
setItemVisible = (id, visible) => {
|
||||
let element = document.querySelector('#' + id);
|
||||
element.style.display = visible ? null : 'none';
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{marginTop: 15}}>
|
||||
<button onClick={this.addFiveItems}>Add Five Items</button>
|
||||
<button onClick={this.removeSelected}>Remove Selected</button>
|
||||
<button onClick={this.updatePrices}>Update Prices</button>
|
||||
|
||||
<span style={{padding: 10}}/>
|
||||
<button id="groupingOn" onClick={() => this.setGroupingEnabled(true)}>Turn Grouping On</button>
|
||||
<button id="groupingOff" style={{display: "none"}} onClick={() => this.setGroupingEnabled(false)}>Turn
|
||||
Grouping {this.state.groupingOn ? "Off" : "On"}
|
||||
</button>
|
||||
<span style={{padding: 10}}/>
|
||||
<span style={{border: "1px solid lightgrey", padding: 4}}>
|
||||
Group Selected Rows:
|
||||
<button onClick={() => this.setSelectedToGroup('A')}>A</button>
|
||||
<button onClick={() => this.setSelectedToGroup('B')}>B</button>
|
||||
<button onClick={() => this.setSelectedToGroup('C')}>C</button>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// the following methods are for creating dummy row data
|
||||
createRowData() {
|
||||
let rowData = [];
|
||||
|
||||
for (let i = 0; i < 14; i++) {
|
||||
let newItem = this.createItem();
|
||||
rowData.push(newItem);
|
||||
}
|
||||
|
||||
return rowData;
|
||||
}
|
||||
|
||||
createItem() {
|
||||
return {
|
||||
group: 'A',
|
||||
symbol: this.createUniqueRandomSymbol(),
|
||||
price: Math.floor(Math.random() * 100)
|
||||
};
|
||||
}
|
||||
|
||||
// creates a unique symbol, eg 'ADG' or 'ZJD'
|
||||
createUniqueRandomSymbol() {
|
||||
let symbol;
|
||||
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
let isUnique = false;
|
||||
while (!isUnique) {
|
||||
symbol = '';
|
||||
// create symbol
|
||||
for (let i = 0; i < 3; i++) {
|
||||
symbol += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
}
|
||||
// check uniqueness
|
||||
isUnique = true;
|
||||
this.props.rowData.forEach(function (oldItem) {
|
||||
if (oldItem.symbol === symbol) {
|
||||
isUnique = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
// pull off row data and selected row changes
|
||||
export default connect(
|
||||
(state) => {
|
||||
return {
|
||||
rowData: state.rowData,
|
||||
rowSelection: state.rowSelection
|
||||
}
|
||||
}
|
||||
)(HeaderComponent);
|
||||
@@ -1,41 +0,0 @@
|
||||
import React, {Component} from "react";
|
||||
import {Provider} from "react-redux";
|
||||
import {createStore} from "redux";
|
||||
|
||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||
import "ag-grid-enterprise";
|
||||
|
||||
import HeaderComponent from "./HeaderComponent";
|
||||
import GridComponent from "./GridComponent";
|
||||
|
||||
import gridData from "./gridDataReducer";
|
||||
|
||||
let store = createStore(gridData);
|
||||
|
||||
/*
|
||||
* This component serves as a container for both the header and grid components. It's primarily here to act as a container
|
||||
* for the redux Provider
|
||||
*/
|
||||
export default class SimpleReduxExample extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setGroupingEnabled = this.setGroupingEnabled.bind(this);
|
||||
}
|
||||
|
||||
setGroupingEnabled(enabled) {
|
||||
this.grid.setGroupingEnabled(enabled);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<div>
|
||||
<h1>Simple Redux Example using ag-Grid's deltaRowMode</h1>
|
||||
<HeaderComponent setGroupingEnabled={this.setGroupingEnabled} />
|
||||
<GridComponent ref={ grid => { this.grid = grid ? grid.getWrappedInstance() : null }} />
|
||||
</div>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
export function updateRowData(rowData) {
|
||||
return {
|
||||
type: 'ROW_DATA_CHANGED',
|
||||
rowData
|
||||
}
|
||||
}
|
||||
|
||||
export function updateRowSelection(rowSelection) {
|
||||
return {
|
||||
type: 'ROW_SELECTION_CHANGED',
|
||||
rowSelection
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
export default (state = {rowData: [], rowSelection: []}, action) => {
|
||||
switch (action.type) {
|
||||
case 'ROW_DATA_CHANGED':
|
||||
return {
|
||||
...state,
|
||||
rowData: action.rowData,
|
||||
};
|
||||
case 'ROW_SELECTION_CHANGED':
|
||||
return {
|
||||
...state,
|
||||
rowSelection: action.rowSelection,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user