AG-420 Improve React implementation
BIN
images/alberto.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
images/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
images/fire.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
images/flags/ar.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
images/flags/br.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
images/flags/co.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
images/flags/de.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
images/flags/es.png
Normal file
|
After Width: | Height: | Size: 174 B |
BIN
images/flags/fr.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
images/flags/gb.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
images/flags/gr.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
images/flags/ie.png
Normal file
|
After Width: | Height: | Size: 119 B |
BIN
images/flags/is.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
images/flags/it.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
images/flags/mt.png
Normal file
|
After Width: | Height: | Size: 136 B |
BIN
images/flags/no.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
images/flags/pe.png
Normal file
|
After Width: | Height: | Size: 89 B |
BIN
images/flags/pt.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
images/flags/se.png
Normal file
|
After Width: | Height: | Size: 97 B |
BIN
images/flags/uy.png
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
images/flags/ve.png
Normal file
|
After Width: | Height: | Size: 173 B |
BIN
images/frost.png
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
images/horse.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
images/niall.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
images/phone.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
images/sean.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
images/smiley-sad.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
images/smiley.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
images/statue.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
images/sun.png
Normal file
|
After Width: | Height: | Size: 570 B |
@@ -32,50 +32,58 @@ class TopMoversGrid extends Component {
|
||||
headerName: '% NC',
|
||||
headerClass: 'align-right',
|
||||
cellRenderer: 'animateShowChange',
|
||||
cellClass: 'align-right'
|
||||
cellClass: 'align-right',
|
||||
cellFormatter(params) {
|
||||
return params.value.toFixed(2)
|
||||
}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
// grid events
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||
}
|
||||
|
||||
getRowNodeId(data) {
|
||||
return data.symbol;
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
if (this.props.rowData) {
|
||||
this.gridApi.setRowData(this.props.rowData);
|
||||
}
|
||||
// if (this.props.rowData) {
|
||||
// this.gridApi.setRowData(this.props.rowData);
|
||||
// }
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
let newRowData = nextProps.rowData;
|
||||
let model = this.gridApi.getModel();
|
||||
|
||||
// remove nodes not in new data set
|
||||
let nodesToRemove = [];
|
||||
for (let rowIndex = 0; rowIndex < model.getRowCount(); rowIndex++) {
|
||||
let rowNode = model.getRow(rowIndex);
|
||||
if (rowNode.data.symbol !== newRowData[rowIndex].symbol) {
|
||||
nodesToRemove.push(rowNode);
|
||||
}
|
||||
}
|
||||
this.gridApi.removeItems(nodesToRemove);
|
||||
|
||||
// add new items in set
|
||||
for (let rowIndex = 0; rowIndex < newRowData.length; rowIndex++) {
|
||||
let model = this.gridApi.getModel();
|
||||
let rowNode = model.getRow(rowIndex);
|
||||
|
||||
if (!rowNode ||
|
||||
rowNode.data.symbol !== newRowData[rowIndex].symbol) {
|
||||
this.gridApi.insertItemsAtIndex(rowIndex, [newRowData[rowIndex]])
|
||||
}
|
||||
}
|
||||
}
|
||||
// componentWillReceiveProps(nextProps) {
|
||||
// let newRowData = nextProps.rowData;
|
||||
// let model = this.gridApi.getModel();
|
||||
//
|
||||
// // remove nodes not in new data set
|
||||
// let nodesToRemove = [];
|
||||
// for (let rowIndex = 0; rowIndex < model.getRowCount(); rowIndex++) {
|
||||
// let rowNode = model.getRow(rowIndex);
|
||||
// if (rowNode.data.symbol !== newRowData[rowIndex].symbol) {
|
||||
// nodesToRemove.push(rowNode);
|
||||
// }
|
||||
// }
|
||||
// this.gridApi.removeItems(nodesToRemove);
|
||||
//
|
||||
// // add new items in set
|
||||
// for (let rowIndex = 0; rowIndex < newRowData.length; rowIndex++) {
|
||||
// let model = this.gridApi.getModel();
|
||||
// let rowNode = model.getRow(rowIndex);
|
||||
//
|
||||
// if (!rowNode ||
|
||||
// rowNode.data.symbol !== newRowData[rowIndex].symbol) {
|
||||
// this.gridApi.insertItemsAtIndex(rowIndex, [newRowData[rowIndex]])
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
render() {
|
||||
return (
|
||||
@@ -84,9 +92,12 @@ class TopMoversGrid extends Component {
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
enableSorting="false"
|
||||
rowData={this.props.rowData}
|
||||
enableSorting="true"
|
||||
enableFilter="false"
|
||||
animateRows="true"
|
||||
enableImmutableMode="true"
|
||||
getRowNodeId={this.getRowNodeId}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
|
||||
50
src/App.jsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import React, {Component} from "react";
|
||||
import {Route, Switch, NavLink, Redirect} from "react-router-dom";
|
||||
|
||||
import NavItem from "./NavItem";
|
||||
|
||||
import DynamicComponentsExample from "./dynamicComponentExample/DynamicComponentsExample";
|
||||
import RichComponentsExample from "./richComponentExample/RichComponentsExample";
|
||||
import EditorComponentsExample from "./editorComponentExample/EditorComponentsExample";
|
||||
|
||||
const Header = () => (
|
||||
<header>
|
||||
<ul className="nav nav-pills">
|
||||
<NavItem to='/rich-grid'>Rich Grid Example</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='/master-detail'>Master Detail Example</NavItem>
|
||||
<NavItem to='/grouped-data'>Grouped Data Example</NavItem>
|
||||
</ul>
|
||||
</header>
|
||||
)
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Header/>
|
||||
<Switch>
|
||||
<Redirect from="/" exact to="/dynamic" />
|
||||
{/*<Route exact path='/rich-dynamic' component={DynamicComponentsExample}/>*/}
|
||||
<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={RichComponentsExample}/>*/}
|
||||
{/*<Route exact path='/full-width' component={RichComponentsExample}/>*/}
|
||||
{/*<Route exact path='/group-row' component={RichComponentsExample}/>*/}
|
||||
{/*<Route exact path='/filter' component={RichComponentsExample}/>*/}
|
||||
{/*<Route exact path='/master-detail' component={RichComponentsExample}/>*/}
|
||||
{/*<Route exact path='/grouped-data' component={RichComponentsExample}/>*/}
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default App
|
||||
19
src/NavItem.jsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React, {PropTypes} from 'react'
|
||||
import {Route, Link} from 'react-router-dom'
|
||||
|
||||
// for bootstrap li active functionality
|
||||
export default function NavItem({children, to, exact}) {
|
||||
return (
|
||||
<Route path={to} exact={exact} children={({match}) => (
|
||||
<li className={match ? 'active' : null}>
|
||||
<Link to={to}>{children}</Link>
|
||||
</li>
|
||||
)}/>
|
||||
)
|
||||
}
|
||||
|
||||
NavItem.propTypes = {
|
||||
to: PropTypes.string.isRequired,
|
||||
exact: PropTypes.bool,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
19
src/dynamicComponentExample/ChildMessageRenderer.jsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class ChildMessageRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.invokeParentMethod = this.invokeParentMethod.bind(this);
|
||||
}
|
||||
|
||||
invokeParentMethod() {
|
||||
this.props.context.componentParent.methodFromParent(`Row: ${this.props.node.rowIndex}, Col: ${this.props.colDef.headerName}`)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span><button style={{height: 20}} onClick={this.invokeParentMethod}>Invoke Parent</button></span>
|
||||
);
|
||||
}
|
||||
};
|
||||
21
src/dynamicComponentExample/CubeRenderer.jsx
Normal file
@@ -0,0 +1,21 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
};
|
||||
17
src/dynamicComponentExample/CurrencyRenderer.jsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import React, {Component} from "react";
|
||||
|
||||
export default class CurrencyRenderer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
formatValueToCurrency(currency, value) {
|
||||
return `${currency}${value}`
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{this.formatValueToCurrency('EUR', this.props.value)}</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
123
src/dynamicComponentExample/DynamicComponentsExample.jsx
Normal file
@@ -0,0 +1,123 @@
|
||||
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: this.createRowData(),
|
||||
|
||||
columnDefs: this.createColumnDefs()
|
||||
};
|
||||
|
||||
this.onGridReady = this.onGridReady.bind(this);
|
||||
this.refreshRowData = this.refreshRowData.bind(this);
|
||||
}
|
||||
|
||||
onGridReady(params) {
|
||||
this.gridApi = params.api;
|
||||
this.columnApi = params.columnApi;
|
||||
|
||||
this.gridApi.sizeColumnsToFit();
|
||||
}
|
||||
|
||||
onCellValueChanged($event) {
|
||||
this.gridApi.refreshCells([$event.node],["cube"]);
|
||||
}
|
||||
|
||||
methodFromParent(cell) {
|
||||
alert(`Parent Component Method from ${cell}!`);
|
||||
}
|
||||
|
||||
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: "params",
|
||||
width: 135
|
||||
},
|
||||
{
|
||||
headerName: "Child/Parent",
|
||||
field: "value",
|
||||
cellRendererFramework: ChildMessageRenderer,
|
||||
colId: "params",
|
||||
width: 120
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
refreshRowData() {
|
||||
let rowData = this.createRowData();
|
||||
this.gridApi.setRowData(rowData);
|
||||
}
|
||||
|
||||
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={{width: 800, height: 400}}
|
||||
className="ag-fresh">
|
||||
<h1>Dynamic React Component Example</h1>
|
||||
<button onClick={this.refreshRowData}>Refresh Data</button>
|
||||
<AgGridReact
|
||||
// properties
|
||||
columnDefs={this.state.columnDefs}
|
||||
rowData={this.state.rowData}
|
||||
gridOptions={this.state.gridOptions}
|
||||
|
||||
// events
|
||||
onGridReady={this.onGridReady}>
|
||||
</AgGridReact>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
13
src/dynamicComponentExample/ParamsRenderer.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
};
|
||||
21
src/dynamicComponentExample/SquareRenderer.jsx
Normal file
@@ -0,0 +1,21 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
};
|
||||
82
src/editorComponentExample/EditorComponentsExample.jsx
Normal file
@@ -0,0 +1,82 @@
|
||||
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: 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: "Name", field: "name", width: 300},
|
||||
{
|
||||
headerName: "Mood",
|
||||
field: "mood",
|
||||
cellRendererFramework: MoodRenderer,
|
||||
cellEditorFramework: MoodEditor,
|
||||
editable: true,
|
||||
width: 250
|
||||
},
|
||||
{
|
||||
headerName: "Numeric",
|
||||
field: "number",
|
||||
cellEditorFramework: NumericEditor,
|
||||
editable: true,
|
||||
width: 250
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
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={{width: 800, height: 400}}
|
||||
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>
|
||||
);
|
||||
}
|
||||
};
|
||||
108
src/editorComponentExample/MoodEditor.jsx
Normal file
@@ -0,0 +1,108 @@
|
||||
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.onKeyDown = this.onKeyDown.bind(this);
|
||||
|
||||
this.state = {
|
||||
happy: false
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setHappy(this.props.value === "Happy");
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
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",
|
||||
// outline: "none"
|
||||
};
|
||||
|
||||
let unselected = {
|
||||
paddingLleft: 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.value === 'Happy' ? selected : unselected;
|
||||
let sadStyle = this.state.value !== 'Happy' ? selected : unselected;
|
||||
|
||||
return (
|
||||
<div ref="container"
|
||||
style={mood}>
|
||||
<img src="images/smiley.png" onClick={this.onHappyClick} style={happyStyle}/>
|
||||
<img src="images/smiley-sad.png" onClick={this.onSadClick} style={sadStyle}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
27
src/editorComponentExample/MoodRenderer.jsx
Normal file
@@ -0,0 +1,27 @@
|
||||
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}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
83
src/editorComponentExample/NumericEditor.jsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import React, {Component} from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
export default class MoodEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: this.props.value
|
||||
};
|
||||
|
||||
this.cancelBeforeStart = this.props.charPress && ('1234567890'.indexOf(this.props.charPress) < 0);
|
||||
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.focus();
|
||||
}
|
||||
|
||||
focus() {
|
||||
setTimeout(() => {
|
||||
let container = ReactDOM.findDOMNode(this.refs.input);
|
||||
if (container) {
|
||||
container.focus();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
onKeyDown(event) {
|
||||
if (!this.isKeyPressedNumeric(event)) {
|
||||
if (event.preventDefault) event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(event) {
|
||||
this.setState({value: event.target.value});
|
||||
}
|
||||
|
||||
getCharCodeFromEvent(event) {
|
||||
event = event || window.event;
|
||||
return (typeof event.which === "undefined") ? event.keyCode : event.which;
|
||||
}
|
||||
|
||||
isCharNumeric(charStr) {
|
||||
return !!/\d/.test(charStr);
|
||||
}
|
||||
|
||||
isKeyPressedNumeric(event) {
|
||||
const charCode = this.getCharCodeFromEvent(event);
|
||||
const charStr = event.key ? event.key : String.fromCharCode(charCode);
|
||||
return this.isCharNumeric(charStr);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<input ref="input"
|
||||
value={this.state.value}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
BIN
src/images/alberto.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
src/images/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/images/fire.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
src/images/flags/ar.png
Normal file
|
After Width: | Height: | Size: 128 B |
BIN
src/images/flags/br.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
src/images/flags/co.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
src/images/flags/de.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
src/images/flags/es.png
Normal file
|
After Width: | Height: | Size: 174 B |
BIN
src/images/flags/fr.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
src/images/flags/gb.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
src/images/flags/gr.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
src/images/flags/ie.png
Normal file
|
After Width: | Height: | Size: 119 B |
BIN
src/images/flags/is.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
src/images/flags/it.png
Normal file
|
After Width: | Height: | Size: 94 B |
BIN
src/images/flags/mt.png
Normal file
|
After Width: | Height: | Size: 136 B |
BIN
src/images/flags/no.png
Normal file
|
After Width: | Height: | Size: 154 B |
BIN
src/images/flags/pe.png
Normal file
|
After Width: | Height: | Size: 89 B |
BIN
src/images/flags/pt.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
src/images/flags/se.png
Normal file
|
After Width: | Height: | Size: 97 B |
BIN
src/images/flags/uy.png
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
src/images/flags/ve.png
Normal file
|
After Width: | Height: | Size: 173 B |
BIN
src/images/frost.png
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
src/images/horse.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src/images/niall.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
src/images/phone.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/images/sean.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
src/images/skills/android.png
Normal file
|
After Width: | Height: | Size: 883 B |
BIN
src/images/skills/css.png
Normal file
|
After Width: | Height: | Size: 902 B |
BIN
src/images/skills/html5.png
Normal file
|
After Width: | Height: | Size: 953 B |
BIN
src/images/skills/mac.png
Normal file
|
After Width: | Height: | Size: 394 B |
BIN
src/images/skills/windows.png
Normal file
|
After Width: | Height: | Size: 893 B |
BIN
src/images/smiley-sad.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/images/smiley.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/images/statue.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
src/images/sun.png
Normal file
|
After Width: | Height: | Size: 570 B |
18
src/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="dist/bundle.js" charset="utf-8"></script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
21
src/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
import React from "react";
|
||||
import {render} from "react-dom";
|
||||
import {BrowserRouter} from "react-router-dom";
|
||||
|
||||
import "ag-grid-root/dist/styles/ag-grid.css";
|
||||
import "ag-grid-root/dist/styles/theme-fresh.css";
|
||||
import "../node_modules/bootstrap/dist/css/bootstrap.css";
|
||||
|
||||
import App from "./App";
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<App/>
|
||||
</BrowserRouter>,
|
||||
document.querySelector('#app')
|
||||
);
|
||||
});
|
||||
|
||||
26
src/richComponentExample/ClickableRenderer.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
this.clicked = this.clicked.bind(this);
|
||||
}
|
||||
|
||||
clicked() {
|
||||
console.log("Child Cell Clicked: " + JSON.stringify(this.state.cell));
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<button style={{height: 21}} onClick={this.clicked} >Click Me</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
41
src/richComponentExample/RatioRenderer.jsx
Normal file
@@ -0,0 +1,41 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
78
src/richComponentExample/RichComponentsExample.jsx
Normal file
@@ -0,0 +1,78 @@
|
||||
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: 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: "Name", field: "name", width: 200},
|
||||
{
|
||||
headerName: "Ratio Component",
|
||||
field: "ratios",
|
||||
cellRendererFramework: RatioRenderer,
|
||||
width: 350
|
||||
},
|
||||
{
|
||||
headerName: "Clickable Component",
|
||||
field: "name",
|
||||
cellRendererFramework: ClickableRenderer,
|
||||
width: 250
|
||||
}
|
||||
]; }
|
||||
|
||||
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={{width: 800, height: 400}}
|
||||
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>
|
||||
);
|
||||
}
|
||||
};
|
||||
42
webpack.config.examples.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const path = require('path');
|
||||
|
||||
const SRC_DIR = path.resolve(__dirname, 'src');
|
||||
|
||||
module.exports = {
|
||||
entry: SRC_DIR + "/index.js",
|
||||
output: {
|
||||
path: __dirname,
|
||||
filename: "dist/bundle.js"
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: "style!css"
|
||||
},
|
||||
{
|
||||
test: /\.js$|\.jsx$/,
|
||||
include: SRC_DIR,
|
||||
loader: 'babel-loader',
|
||||
query: {
|
||||
presets: ['react', 'es2015', 'stage-0']
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
|
||||
loader: 'file?name=[path]/[name].[ext]'
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"ag-grid-root" : __dirname + "/node_modules/ag-grid"
|
||||
},
|
||||
extensions: ['', '.js', '.jsx']
|
||||
},
|
||||
devServer: {
|
||||
historyApiFallback: true,
|
||||
contentBase: './',
|
||||
hot: true
|
||||
}
|
||||
};
|
||||