Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2228a8d0c9 | ||
|
|
9528d5a5bc | ||
|
|
3b5eaac21a | ||
|
|
73cc989512 | ||
|
|
5a45846cb7 | ||
|
|
2d8d5b125e | ||
|
|
818b7798ee | ||
|
|
15ba8d7e60 | ||
|
|
eab958c3e9 | ||
|
|
3a17b7f638 | ||
|
|
734d39e2d7 | ||
|
|
0d7cace354 | ||
|
|
fa0881bfcf | ||
|
|
62b9e3582a | ||
|
|
949797d4be | ||
|
|
a869fe3819 | ||
|
|
c611af4f39 | ||
|
|
7cab3190ae | ||
|
|
71fe653fcb | ||
|
|
ba1c213ce0 | ||
|
|
46217c9ad7 | ||
|
|
017642e4d7 | ||
|
|
79b0eda61b | ||
|
|
a70f248af5 | ||
|
|
32142b435b | ||
|
|
d71781899d | ||
|
|
9560f86bf5 | ||
|
|
9f4b270884 | ||
|
|
e5627d8b9f | ||
|
|
f8f0c21af2 | ||
|
|
b54d549959 | ||
|
|
464a0ea9f4 | ||
|
|
675cbe497c | ||
|
|
a4dbbf529d |
11
README.md
11
README.md
@@ -4,7 +4,14 @@ ag-Grid React Example
|
|||||||
|
|
||||||
Examples of running ag-Grid inside React application.
|
Examples of running ag-Grid inside React application.
|
||||||
|
|
||||||
See the [www.ag-grid.com](http://www.ag-grid.com).
|
See [www.ag-grid.com](http://www.ag-grid.com) for an overview and full documentation.
|
||||||
|
|
||||||
|
Frameworks Supported
|
||||||
|
====================
|
||||||
|
Framework specific Getting Started guides:
|
||||||
|
[Angular 1](https://www.ag-grid.com/best-angularjs-data-grid/) | [Angular 2](https://www.ag-grid.com/best-angular-2-data-grid/) | [Aurelia](https://www.ag-grid.com/best-aurelia-data-grid/)
|
||||||
|
[Javascript](https://www.ag-grid.com/best-javascript-data-grid/) | [React](https://www.ag-grid.com/best-react-data-grid/) | [TypeScript](https://www.ag-grid.com/ag-grid-typescript-webpack-2/)
|
||||||
|
[VueJS](https://www.ag-grid.com/best-vuejs-data-grid/) | [Web Components](https://www.ag-grid.com/best-web-component-data-grid/)
|
||||||
|
|
||||||
There are two examples:
|
There are two examples:
|
||||||
|
|
||||||
@@ -18,5 +25,5 @@ Building
|
|||||||
To build:
|
To build:
|
||||||
- `npm install`
|
- `npm install`
|
||||||
- `npm install webpack -g`
|
- `npm install webpack -g`
|
||||||
- `npm run standard` or `npm run large`
|
- `npm run example`, `npm run large` or `npm run trader`
|
||||||
- navigate to localhost:8080
|
- navigate to localhost:8080
|
||||||
26
gulpfile.js
Normal file
26
gulpfile.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const gulpTypescript = require('gulp-typescript');
|
||||||
|
const merge = require('merge2');
|
||||||
|
|
||||||
|
gulp.task('watch', watchTask);
|
||||||
|
gulp.task('rebuild-ag-grid-react', rebuildAgGridReact);
|
||||||
|
|
||||||
|
const tsConfig = '../ag-grid-react/tsconfig.json';
|
||||||
|
const tsProject = gulpTypescript.createProject(tsConfig);
|
||||||
|
|
||||||
|
function rebuildAgGridReact() {
|
||||||
|
const tsResult = gulp
|
||||||
|
.src('../ag-grid-react/src/**/*.ts')
|
||||||
|
.pipe(tsProject());
|
||||||
|
|
||||||
|
return merge([
|
||||||
|
tsResult.dts
|
||||||
|
.pipe(gulp.dest('node_modules/ag-grid-react/lib')),
|
||||||
|
tsResult.js
|
||||||
|
.pipe(gulp.dest('node_modules/ag-grid-react/lib'))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchTask() {
|
||||||
|
gulp.watch(['../ag-grid-react/src/**/*'], rebuildAgGridReact);
|
||||||
|
}
|
||||||
32
package.json
32
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ag-grid-react-example",
|
"name": "ag-grid-react-example",
|
||||||
"version": "10.0.0",
|
"version": "13.1.0",
|
||||||
"description": "Example Reach applicaiton using ag-Grid.",
|
"description": "Example Reach applicaiton using ag-Grid.",
|
||||||
"main": "dist/ag-grid-react-example.js",
|
"main": "dist/ag-grid-react-example.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -12,16 +12,18 @@
|
|||||||
"copy-examples": "ncp images dist/examples/images && ncp src/index.html dist/examples/index.html && ncp dist/react-examples.js dist/examples/dist/react-examples.js && ncp src dist/examples/src",
|
"copy-examples": "ncp images dist/examples/images && ncp src/index.html dist/examples/index.html && ncp dist/react-examples.js dist/examples/dist/react-examples.js && ncp src dist/examples/src",
|
||||||
"copy-trader": "ncp src-trader-dashboard/index.html dist/trader/index.html && ncp dist/react-trader.js dist/trader/dist/react-trader.js",
|
"copy-trader": "ncp src-trader-dashboard/index.html dist/trader/index.html && ncp dist/react-trader.js dist/trader/dist/react-trader.js",
|
||||||
"copy": "npm run copy-examples && npm run copy-trader",
|
"copy": "npm run copy-examples && npm run copy-trader",
|
||||||
|
"build-large": "webpack --config webpack.config.large.js --progress --profile --bail",
|
||||||
"build-examples": "webpack --config webpack.config.examples.js --progress --profile --bail",
|
"build-examples": "webpack --config webpack.config.examples.js --progress --profile --bail",
|
||||||
"build-dashboard": "webpack --config webpack.config.trader.js --progress --profile --bail",
|
"build-dashboard": "webpack --config webpack.config.trader.js --progress --profile --bail",
|
||||||
"build-all": "npm run build-examples && npm run build-dashboard",
|
"build-all": "npm run build-examples && npm run build-dashboard",
|
||||||
"build": "npm run clean && npm run mkdirs && npm run build-all && npm run copy",
|
"build": "npm run clean && npm run mkdirs && npm run build-all && npm run copy",
|
||||||
"copy-to-docs": "ncp dist/examples ../ag-grid-docs/src/react-examples/examples && ncp dist/trader ../ag-grid-docs/src/react-examples/trader",
|
"copy-to-docs": "ncp dist/examples ../ag-grid-docs/src/framework-examples/react-examples/examples && ncp dist/trader ../ag-grid-docs/src/framework-examples/react-examples/trader",
|
||||||
"build-to-docs": "npm run build && npm run copy-to-docs"
|
"build-to-docs": "npm run build && npm run copy-to-docs",
|
||||||
|
"start": "npm run examples"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ceolter/ag-grid-react-example.git"
|
"url": "https://github.com/ag-grid/ag-grid-react-example.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
@@ -32,7 +34,7 @@
|
|||||||
"author": "Niall Crosby <niall.crosby@gmail.com>",
|
"author": "Niall Crosby <niall.crosby@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/ceolter/ag-grid-react-example/issues"
|
"url": "https://github.com/ag-grid/ag-grid-react-example/issues"
|
||||||
},
|
},
|
||||||
"homepage": "http://www.ag-grid.com/",
|
"homepage": "http://www.ag-grid.com/",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -45,25 +47,29 @@
|
|||||||
"css-loader": "0.23.x",
|
"css-loader": "0.23.x",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
|
"prop-types": "15.5.x",
|
||||||
"rimraf": "2.5.x",
|
"rimraf": "2.5.x",
|
||||||
"style-loader": "0.13.x",
|
"style-loader": "0.13.x",
|
||||||
"webpack": "1.12.x",
|
"webpack": "1.12.x",
|
||||||
"webpack-dev-server": "1.14.x"
|
"webpack-dev-server": "1.14.x",
|
||||||
|
"gulp": "3.9.x",
|
||||||
|
"gulp-typescript": "3.1.x",
|
||||||
|
"merge2": "1.0.x",
|
||||||
|
"typescript": "2.3.x"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "3.3.7",
|
"bootstrap": "3.3.7",
|
||||||
"d3": "4.9.1",
|
"d3": "4.9.1",
|
||||||
"file-loader": "0.11.1",
|
"file-loader": "0.11.1",
|
||||||
"lodash": "4.17.4",
|
"lodash": "4.17.4",
|
||||||
"react": "15.5.x",
|
"react": "15.6.x",
|
||||||
"react-dom": "15.5.x",
|
"react-dom": "15.6.x",
|
||||||
|
"react-dom-factories": "1.0.0",
|
||||||
"react-redux": "5.0.x",
|
"react-redux": "5.0.x",
|
||||||
"redux": "3.6.x",
|
"redux": "3.6.x",
|
||||||
"url-search-params-polyfill": "1.2.0",
|
"url-search-params-polyfill": "1.2.0",
|
||||||
"ag-grid": "10.1.x",
|
"ag-grid": "13.1.x",
|
||||||
"ag-grid-enterprise": "10.1.x",
|
"ag-grid-enterprise": "13.1.x",
|
||||||
"ag-grid-react": "10.1.x"
|
"ag-grid-react": "13.1.x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class SimpleCellRenderer extends React.Component {
|
export default class SimpleCellRenderer extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
@@ -11,5 +12,5 @@ export default class SimpleCellRenderer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SimpleCellRenderer.propTypes = {
|
SimpleCellRenderer.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -16,6 +16,9 @@ class FxQuoteMatrix extends Component {
|
|||||||
|
|
||||||
// grid events
|
// grid events
|
||||||
this.onGridReady = this.onGridReady.bind(this);
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
|
|
||||||
|
// grid callbacks
|
||||||
|
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onGridReady(params) {
|
onGridReady(params) {
|
||||||
@@ -27,34 +30,31 @@ class FxQuoteMatrix extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRowNodeId(data) {
|
||||||
|
return data.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const newRowData = nextProps.rowData;
|
const newRowData = nextProps.rowData;
|
||||||
|
|
||||||
const updatedNodes = [];
|
const updatedRows = [];
|
||||||
const updatedCols = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < newRowData.length; i++) {
|
for (let i = 0; i < newRowData.length; i++) {
|
||||||
// note that for this use case we assume the existing and new row data have the same
|
|
||||||
// row and column order
|
|
||||||
let node = this.gridApi.getModel().getRow(i);
|
|
||||||
let newRow = newRowData[i];
|
let newRow = newRowData[i];
|
||||||
|
let currentRowNode = this.gridApi.getRowNode(newRow.symbol);
|
||||||
|
|
||||||
const {data} = node;
|
const {data} = currentRowNode;
|
||||||
let updated = false;
|
|
||||||
for (const def of this.state.columnDefs) {
|
for (const def of this.state.columnDefs) {
|
||||||
if (data[def.field] !== newRow[def.field]) {
|
if (data[def.field] !== newRow[def.field]) {
|
||||||
updatedCols.push(def.field);
|
updatedRows.push(newRow);
|
||||||
|
break;
|
||||||
updated = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
|
||||||
assign(data, newRow);
|
|
||||||
updatedNodes.push(node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.gridApi.refreshCells(updatedNodes, uniq(updatedCols));
|
|
||||||
|
this.gridApi.updateRowData({update: updatedRows});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -67,6 +67,9 @@ class FxQuoteMatrix extends Component {
|
|||||||
enableSorting="false"
|
enableSorting="false"
|
||||||
enableFilter="false"
|
enableFilter="false"
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
getRowNodeId={this.getRowNodeId}
|
||||||
|
|
||||||
// events
|
// events
|
||||||
onGridReady={this.onGridReady}>
|
onGridReady={this.onGridReady}>
|
||||||
</AgGridReact>
|
</AgGridReact>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import map from "lodash/map";
|
|||||||
import difference from "lodash/difference";
|
import difference from "lodash/difference";
|
||||||
import forEach from "lodash/forEach";
|
import forEach from "lodash/forEach";
|
||||||
import includes from "lodash/includes";
|
import includes from "lodash/includes";
|
||||||
import assign from "lodash/assign";
|
|
||||||
|
|
||||||
import ExchangeService from "../services/ExchangeService.jsx";
|
import ExchangeService from "../services/ExchangeService.jsx";
|
||||||
|
|
||||||
@@ -24,21 +23,21 @@ export default class extends Component {
|
|||||||
{
|
{
|
||||||
field: 'price',
|
field: 'price',
|
||||||
headerName: 'Price',
|
headerName: 'Price',
|
||||||
cellFormatter: this.numberFormatter,
|
valueFormatter: this.numberFormatter,
|
||||||
cellRenderer: 'animateShowChange',
|
cellRenderer: 'animateShowChange',
|
||||||
cellStyle: {'text-align': 'right'}
|
cellStyle: {'text-align': 'right'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'bid',
|
field: 'bid',
|
||||||
headerName: 'Bid',
|
headerName: 'Bid',
|
||||||
cellFormatter: this.numberFormatter,
|
valueFormatter: this.numberFormatter,
|
||||||
cellRenderer: 'animateShowChange',
|
cellRenderer: 'animateShowChange',
|
||||||
cellStyle: {'text-align': 'right'}
|
cellStyle: {'text-align': 'right'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'ask',
|
field: 'ask',
|
||||||
headerName: 'Ask',
|
headerName: 'Ask',
|
||||||
cellFormatter: this.numberFormatter,
|
valueFormatter: this.numberFormatter,
|
||||||
cellRenderer: 'animateShowChange',
|
cellRenderer: 'animateShowChange',
|
||||||
cellStyle: {'text-align': 'right'}
|
cellStyle: {'text-align': 'right'}
|
||||||
}
|
}
|
||||||
@@ -51,6 +50,9 @@ export default class extends Component {
|
|||||||
this.onGridReady = this.onGridReady.bind(this);
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
||||||
|
|
||||||
|
// grid callbacks
|
||||||
|
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||||
|
|
||||||
// component events
|
// component events
|
||||||
this.updateSymbol = this.updateSymbol.bind(this);
|
this.updateSymbol = this.updateSymbol.bind(this);
|
||||||
}
|
}
|
||||||
@@ -69,7 +71,7 @@ export default class extends Component {
|
|||||||
|
|
||||||
// make realistic - call in a batch
|
// make realistic - call in a batch
|
||||||
let rowData = map(this.props.selectedExchange.supportedStocks, symbol => this.exchangeService.getTicker(symbol));
|
let rowData = map(this.props.selectedExchange.supportedStocks, symbol => this.exchangeService.getTicker(symbol));
|
||||||
this.gridApi.addItems(rowData);
|
this.gridApi.updateRowData({add: rowData});
|
||||||
|
|
||||||
// select the first symbol to show the chart
|
// select the first symbol to show the chart
|
||||||
this.gridApi.getModel().getRow(0).setSelected(true);
|
this.gridApi.getModel().getRow(0).setSelected(true);
|
||||||
@@ -77,6 +79,10 @@ export default class extends Component {
|
|||||||
this.gridApi.sizeColumnsToFit();
|
this.gridApi.sizeColumnsToFit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRowNodeId(data) {
|
||||||
|
return data.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
onSelectionChanged() {
|
onSelectionChanged() {
|
||||||
let selectedNode = this.gridApi.getSelectedNodes()[0];
|
let selectedNode = this.gridApi.getSelectedNodes()[0];
|
||||||
this.props.onSelectionChanged(selectedNode ? selectedNode.data.symbol : null);
|
this.props.onSelectionChanged(selectedNode ? selectedNode.data.symbol : null);
|
||||||
@@ -108,25 +114,25 @@ export default class extends Component {
|
|||||||
this.exchangeService.removeSubscriber(this.updateSymbol, symbol);
|
this.exchangeService.removeSubscriber(this.updateSymbol, symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove ag-grid nodes as necessary
|
||||||
|
const rowsToRemove = [];
|
||||||
|
this.gridApi.forEachNode(node => {
|
||||||
|
const {data} = node;
|
||||||
|
if (includes(symbolsRemoved, data.symbol)) {
|
||||||
|
rowsToRemove.push(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.gridApi.updateRowData({remove: rowsToRemove});
|
||||||
|
|
||||||
// Subscribe to new ones that need to be added
|
// Subscribe to new ones that need to be added
|
||||||
const symbolsAdded = difference(nextSymbols, currentSymbols);
|
const symbolsAdded = difference(nextSymbols, currentSymbols);
|
||||||
forEach(symbolsAdded, symbol => {
|
forEach(symbolsAdded, symbol => {
|
||||||
this.exchangeService.addSubscriber(this.updateSymbol, symbol);
|
this.exchangeService.addSubscriber(this.updateSymbol, symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove ag-grid nodes as necessary
|
|
||||||
const nodesToRemove = [];
|
|
||||||
this.gridApi.forEachNode(node => {
|
|
||||||
const {data} = node;
|
|
||||||
if (includes(symbolsRemoved, data.symbol)) {
|
|
||||||
nodesToRemove.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.gridApi.removeItems(nodesToRemove);
|
|
||||||
|
|
||||||
// Insert new ag-grid nodes as necessary
|
// Insert new ag-grid nodes as necessary
|
||||||
let rowData = map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol));
|
let rowData = map(symbolsAdded, symbol => this.exchangeService.getTicker(symbol));
|
||||||
this.gridApi.addItems(rowData);
|
this.gridApi.updateRowData({add: rowData});
|
||||||
|
|
||||||
// select the first symbol to show the chart
|
// select the first symbol to show the chart
|
||||||
this.gridApi.getModel().getRow(0).setSelected(true);
|
this.gridApi.getModel().getRow(0).setSelected(true);
|
||||||
@@ -139,24 +145,8 @@ export default class extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedNodes = [];
|
this.gridApi.updateRowData({update: [symbol]});
|
||||||
const updatedCols = [];
|
}
|
||||||
|
|
||||||
this.gridApi.forEachNode(node => {
|
|
||||||
const {data} = node;
|
|
||||||
if (data.symbol === symbol.symbol) {
|
|
||||||
for (const def of this.state.columnDefs) {
|
|
||||||
if (data[def.field] !== symbol[def.field]) {
|
|
||||||
updatedCols.push(def.field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assign(data, symbol);
|
|
||||||
updatedNodes.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.gridApi.refreshCells(updatedNodes, updatedCols);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -168,6 +158,9 @@ export default class extends Component {
|
|||||||
enableSorting="true"
|
enableSorting="true"
|
||||||
rowSelection="single"
|
rowSelection="single"
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
getRowNodeId={this.getRowNodeId}
|
||||||
|
|
||||||
// events
|
// events
|
||||||
onGridReady={this.onGridReady}
|
onGridReady={this.onGridReady}
|
||||||
onSelectionChanged={this.onSelectionChanged}>
|
onSelectionChanged={this.onSelectionChanged}>
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ class TopMoversGrid extends Component {
|
|||||||
|
|
||||||
// grid events
|
// grid events
|
||||||
this.onGridReady = this.onGridReady.bind(this);
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
|
|
||||||
|
// grid callbacks
|
||||||
this.getRowNodeId = this.getRowNodeId.bind(this);
|
this.getRowNodeId = this.getRowNodeId.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, {Component} from "react";
|
import React, {Component} from "react";
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
export default class HorizontalBarComponent extends Component {
|
export default class HorizontalBarComponent extends Component {
|
||||||
|
|
||||||
@@ -38,5 +39,5 @@ export default class HorizontalBarComponent extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HorizontalBarComponent.propTypes = {
|
HorizontalBarComponent.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import concat from "lodash/concat";
|
import concat from "lodash/concat";
|
||||||
import remove from "lodash/remove";
|
|
||||||
import uniq from "lodash/uniq";
|
import uniq from "lodash/uniq";
|
||||||
import find from "lodash/find";
|
import find from "lodash/find";
|
||||||
import sampleSize from "lodash/sampleSize";
|
import sampleSize from "lodash/sampleSize";
|
||||||
@@ -26,7 +25,12 @@ export default class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeSubscriber(subscriber, symbol) {
|
removeSubscriber(subscriber, symbol) {
|
||||||
remove(this.subscribers[symbol], subscriber);
|
let subscribers = this.subscribers[symbol];
|
||||||
|
subscribers.splice(subscribers.indexOf(subscriber), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSubscribers() {
|
||||||
|
this.subscribers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
getTicker(symbol) {
|
getTicker(symbol) {
|
||||||
|
|||||||
19
src/App.jsx
19
src/App.jsx
@@ -6,12 +6,14 @@ import DynamicComponentsExample from "./dynamicComponentExample/DynamicComponent
|
|||||||
import RichGridExample from "./richGridExample/RichGridExample";
|
import RichGridExample from "./richGridExample/RichGridExample";
|
||||||
import RichComponentsExample from "./richComponentExample/RichComponentsExample";
|
import RichComponentsExample from "./richComponentExample/RichComponentsExample";
|
||||||
import EditorComponentsExample from "./editorComponentExample/EditorComponentsExample";
|
import EditorComponentsExample from "./editorComponentExample/EditorComponentsExample";
|
||||||
import FloatingRowComponentExample from "./floatingRowExample/FloatingRowComponentExample";
|
import PinnedRowComponentExample from "./pinnedRowExample/PinnedRowComponentExample";
|
||||||
import FullWidthComponentExample from "./fullWidthExample/FullWidthComponentExample";
|
import FullWidthComponentExample from "./fullWidthExample/FullWidthComponentExample";
|
||||||
import GroupedRowInnerRendererComponentExample from "./groupedRowInnerRendererExample/GroupedRowInnerRendererComponentExample";
|
import GroupedRowInnerRendererComponentExample from "./groupedRowInnerRendererExample/GroupedRowInnerRendererComponentExample";
|
||||||
import FilterComponentExample from "./filterComponentExample/FilterComponentExample";
|
import FilterComponentExample from "./filterComponentExample/FilterComponentExample";
|
||||||
import MasterDetailExample from "./masterDetailExample/MasterDetailExample";
|
import MasterDetailExample from "./masterDetailExample/MasterDetailExample";
|
||||||
import SimpleReduxExample from "./simpleReduxExample/SimpleReduxExample";
|
import SimpleReduxExample from "./simpleReduxExample/SimpleReduxExample";
|
||||||
|
import FloatingFilterGridExample from "./floatingFilter/FloatingFilterGridExample";
|
||||||
|
import SimpleReduxDynamicExample from "./simpleReduxDynamicComponentExample/SimpleReduxExample";
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -30,7 +32,6 @@ class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setExample(example) {
|
setExample(example) {
|
||||||
console.log(example);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
example
|
example
|
||||||
})
|
})
|
||||||
@@ -45,12 +46,14 @@ class App extends Component {
|
|||||||
<li role="presentation" className={this.state.example === 'dynamic' ? 'active' : null} onClick={() => this.setExample("dynamic")}><a href="#">Dynamic React Component Example</a></li>
|
<li role="presentation" className={this.state.example === 'dynamic' ? 'active' : null} onClick={() => this.setExample("dynamic")}><a href="#">Dynamic React Component Example</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'rich-dynamic' ? 'active' : null} onClick={() => this.setExample("rich-dynamic")}><a href="#">Dynamic React Components - Richer Example</a></li>
|
<li role="presentation" className={this.state.example === 'rich-dynamic' ? 'active' : null} onClick={() => this.setExample("rich-dynamic")}><a href="#">Dynamic React Components - Richer Example</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'editor' ? 'active' : null} onClick={() => this.setExample("editor")}><a href="#">Cell Editor Component Example</a></li>
|
<li role="presentation" className={this.state.example === 'editor' ? 'active' : null} onClick={() => this.setExample("editor")}><a href="#">Cell Editor Component Example</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'floating-row' ? 'active' : null} onClick={() => this.setExample("floating-row")}><a href="#">Floating Row Renderer Example</a></li>
|
<li role="presentation" className={this.state.example === 'pinned-row' ? 'active' : null} onClick={() => this.setExample("pinned-row")}><a href="#">Pinned Row Renderer Example</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'full-width' ? 'active' : null} onClick={() => this.setExample("full-width")}><a href="#">Full Width Renderer Example</a></li>
|
<li role="presentation" className={this.state.example === 'full-width' ? 'active' : null} onClick={() => this.setExample("full-width")}><a href="#">Full Width Renderer Example</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'group-row' ? 'active' : null} onClick={() => this.setExample("group-row")}><a href="#">Grouped Row Inner Renderer Example</a></li>
|
<li role="presentation" className={this.state.example === 'group-row' ? 'active' : null} onClick={() => this.setExample("group-row")}><a href="#">Grouped Row Inner Renderer Example</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'filter' ? 'active' : null} onClick={() => this.setExample("filter")}><a href="#">Filters Component Example</a></li>
|
<li role="presentation" className={this.state.example === 'filter' ? 'active' : null} onClick={() => this.setExample("filter")}><a href="#">Filters Component Example</a></li>
|
||||||
|
<li role="presentation" className={this.state.example === 'floating-filter' ? 'active' : null} onClick={() => this.setExample("floating-filter")}><a href="#">Floating Filters</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'master-detail' ? 'active' : null} onClick={() => this.setExample("master-detail")}><a href="#">Master Detail Example</a></li>
|
<li role="presentation" className={this.state.example === 'master-detail' ? 'active' : null} onClick={() => this.setExample("master-detail")}><a href="#">Master Detail Example</a></li>
|
||||||
<li role="presentation" className={this.state.example === 'simple-redux' ? 'active' : null} onClick={() => this.setExample("simple-redux")}><a href="#">Simple Redux Example</a></li>
|
<li role="presentation" className={this.state.example === 'simple-redux' ? 'active' : null} onClick={() => this.setExample("simple-redux")}><a href="#">Simple Redux Example</a></li>
|
||||||
|
<li role="presentation" className={this.state.example === 'simple-redux-dynamic' ? 'active' : null} onClick={() => this.setExample("simple-redux-dynamic")}><a href="#">Simple Redux Dynamic Component Example</a></li>
|
||||||
</ul>)
|
</ul>)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,8 +68,8 @@ class App extends Component {
|
|||||||
case 'editor':
|
case 'editor':
|
||||||
example = <EditorComponentsExample/>;
|
example = <EditorComponentsExample/>;
|
||||||
break;
|
break;
|
||||||
case 'floating-row':
|
case 'pinned-row':
|
||||||
example = <FloatingRowComponentExample/>;
|
example = <PinnedRowComponentExample/>;
|
||||||
break;
|
break;
|
||||||
case 'full-width':
|
case 'full-width':
|
||||||
example = <FullWidthComponentExample/>;
|
example = <FullWidthComponentExample/>;
|
||||||
@@ -83,6 +86,12 @@ class App extends Component {
|
|||||||
case 'simple-redux':
|
case 'simple-redux':
|
||||||
example = <SimpleReduxExample/>;
|
example = <SimpleReduxExample/>;
|
||||||
break;
|
break;
|
||||||
|
case 'floating-filter':
|
||||||
|
example = <FloatingFilterGridExample/>;
|
||||||
|
break;
|
||||||
|
case 'simple-redux-dynamic':
|
||||||
|
example = <SimpleReduxDynamicExample/>;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
example = <RichGridExample/>;
|
example = <RichGridExample/>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,21 @@ export default class MoodEditor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.refs.container.addEventListener('keydown', this.checkAndToggleMoodIfLeftRight);
|
||||||
this.focus();
|
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() {
|
componentDidUpdate() {
|
||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
@@ -75,12 +87,11 @@ export default class MoodEditor extends Component {
|
|||||||
background: "#e6e6e6",
|
background: "#e6e6e6",
|
||||||
padding: 15,
|
padding: 15,
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
display: "inline-block",
|
display: "inline-block"
|
||||||
// outline: "none"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let unselected = {
|
let unselected = {
|
||||||
paddingLleft: 10,
|
paddingLeft: 10,
|
||||||
paddingRight: 10,
|
paddingRight: 10,
|
||||||
border: "1px solid transparent",
|
border: "1px solid transparent",
|
||||||
padding: 4
|
padding: 4
|
||||||
@@ -93,12 +104,14 @@ export default class MoodEditor extends Component {
|
|||||||
padding: 4
|
padding: 4
|
||||||
};
|
};
|
||||||
|
|
||||||
let happyStyle = this.state.value === 'Happy' ? selected : unselected;
|
let happyStyle = this.state.happy ? selected : unselected;
|
||||||
let sadStyle = this.state.value !== 'Happy' ? selected : unselected;
|
let sadStyle = !this.state.happy ? selected : unselected;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref="container"
|
<div ref="container"
|
||||||
style={mood}>
|
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.png" onClick={this.onHappyClick} style={happyStyle}/>
|
||||||
<img src="images/smiley-sad.png" onClick={this.onSadClick} style={sadStyle}/>
|
<img src="images/smiley-sad.png" onClick={this.onSadClick} style={sadStyle}/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export default class MoodEditor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.refs.input.addEventListener('keydown', this.onKeyDown);
|
||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +24,10 @@ export default class MoodEditor extends Component {
|
|||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.refs.input.removeEventListener('keydown', this.onKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let container = ReactDOM.findDOMNode(this.refs.input);
|
let container = ReactDOM.findDOMNode(this.refs.input);
|
||||||
@@ -47,11 +52,20 @@ export default class MoodEditor extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onKeyDown(event) {
|
onKeyDown(event) {
|
||||||
|
if(this.isLeftOrRight(event)) {
|
||||||
|
event.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.isKeyPressedNumeric(event)) {
|
if (!this.isKeyPressedNumeric(event)) {
|
||||||
if (event.preventDefault) event.preventDefault();
|
if (event.preventDefault) event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLeftOrRight(event) {
|
||||||
|
return [37, 39].indexOf(event.keyCode) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
this.setState({value: event.target.value});
|
this.setState({value: event.target.value});
|
||||||
}
|
}
|
||||||
@@ -75,7 +89,6 @@ export default class MoodEditor extends Component {
|
|||||||
return (
|
return (
|
||||||
<input ref="input"
|
<input ref="input"
|
||||||
value={this.state.value}
|
value={this.state.value}
|
||||||
onKeyDown={this.onKeyDown}
|
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ export default class FilterComponentExample extends Component {
|
|||||||
headerName: "Filter Component",
|
headerName: "Filter Component",
|
||||||
field: "name",
|
field: "name",
|
||||||
filterFramework: PartialMatchFilter,
|
filterFramework: PartialMatchFilter,
|
||||||
width: 400
|
width: 400,
|
||||||
|
menuTabs:['filterMenuTab']
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -75,8 +76,6 @@ export default class FilterComponentExample extends Component {
|
|||||||
rowData={this.state.rowData}
|
rowData={this.state.rowData}
|
||||||
|
|
||||||
enableFilter
|
enableFilter
|
||||||
suppressMenuColumnPanel // ag-enterprise only
|
|
||||||
suppressMenuMainPanel // ag-enterprise only
|
|
||||||
|
|
||||||
// events
|
// events
|
||||||
onGridReady={this.onGridReady}>
|
onGridReady={this.onGridReady}>
|
||||||
|
|||||||
69
src/floatingFilter/FloatingFilterGridExample.jsx
Normal file
69
src/floatingFilter/FloatingFilterGridExample.jsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {AgGridReact} from "ag-grid-react";
|
||||||
|
import FloatingFilter from "./floatingFilter";
|
||||||
|
import overrideStyle from "./floatingFilter.css";
|
||||||
|
|
||||||
|
export default class FloatingFilterGridExample extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
columnDefs: this.createColumnDefs(),
|
||||||
|
rowData: this.createRowData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onGridReady(params) {
|
||||||
|
this.gridApi = params.api;
|
||||||
|
this.columnApi = params.columnApi;
|
||||||
|
|
||||||
|
this.gridApi.sizeColumnsToFit();
|
||||||
|
}
|
||||||
|
|
||||||
|
createColumnDefs() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
headerName: "Make",
|
||||||
|
field: "make",
|
||||||
|
floatingFilterComponentFramework: FloatingFilter,
|
||||||
|
filter: 'set'
|
||||||
|
},
|
||||||
|
{headerName: "Model", field: "model"},
|
||||||
|
{headerName: "Price", field: "price"}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
createRowData() {
|
||||||
|
return [
|
||||||
|
{make: "Toyota", model: "Celica", price: 35000},
|
||||||
|
{make: "Ford", model: "Mondeo", price: 32000},
|
||||||
|
{make: "Porsche", model: "Boxter", price: 72000}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let divStyle = {
|
||||||
|
height: 400,
|
||||||
|
width: 945
|
||||||
|
};
|
||||||
|
|
||||||
|
// combine the styles
|
||||||
|
const style = Object.assign({}, divStyle, overrideStyle);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={style} className="ag-fresh">
|
||||||
|
<h1>Floating Filter Example</h1>
|
||||||
|
<AgGridReact
|
||||||
|
// properties
|
||||||
|
columnDefs={this.state.columnDefs}
|
||||||
|
rowData={this.state.rowData}
|
||||||
|
|
||||||
|
floatingFilter={true}
|
||||||
|
|
||||||
|
// events
|
||||||
|
onGridReady={this.onGridReady}>
|
||||||
|
</AgGridReact>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
3
src/floatingFilter/floatingFilter.css
Normal file
3
src/floatingFilter/floatingFilter.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.ag-floating-filter-button button {
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
39
src/floatingFilter/floatingFilter.jsx
Normal file
39
src/floatingFilter/floatingFilter.jsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
|
||||||
|
export default class FloatingFilter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
parentModel: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// when does this get called? how to test this?
|
||||||
|
onParentModelChanged(parentModel) {
|
||||||
|
this.setState({
|
||||||
|
parentModel: parentModel
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(item) {
|
||||||
|
this.props.onFloatingFilterChanged({
|
||||||
|
model: this.state.parentModel.filter(it => it !== item)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.state.parentModel) return null;
|
||||||
|
|
||||||
|
// as the backing filter is a set filter what we're doing here is rendering the list in the set
|
||||||
|
// and when the [x] removing the selected item, thereby effectively hiding it
|
||||||
|
let options = this.state.parentModel.map((item, i) => {
|
||||||
|
let removeMeListener = () => {
|
||||||
|
this.remove(item)
|
||||||
|
};
|
||||||
|
let removeMeElement = <a onClick={removeMeListener}>[x]</a>;
|
||||||
|
return <span key={i}>{item}{removeMeElement}</span>;
|
||||||
|
});
|
||||||
|
|
||||||
|
return <div>{options}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
.ag-group-value .ag-react-container {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,6 @@ import React, {Component} from "react";
|
|||||||
import {AgGridReact} from "ag-grid-react";
|
import {AgGridReact} from "ag-grid-react";
|
||||||
import MedalRenderer from "./MedalRenderer";
|
import MedalRenderer from "./MedalRenderer";
|
||||||
|
|
||||||
import "./GroupedRowInnerRendererComponentExample.css";
|
|
||||||
|
|
||||||
import "ag-grid-enterprise";
|
import "ag-grid-enterprise";
|
||||||
|
|
||||||
export default class GroupedRowInnerRendererComponentExample extends Component {
|
export default class GroupedRowInnerRendererComponentExample extends Component {
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ export default class MedalRenderer extends Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.country = this.props.node.key;
|
this.country = this.props.node.key;
|
||||||
this.gold = this.props.data.gold;
|
this.gold = this.props.node.aggData.gold;
|
||||||
this.silver = this.props.data.silver;
|
this.silver = this.props.node.aggData.silver;
|
||||||
this.bronze = this.props.data.bronze;
|
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() {
|
render() {
|
||||||
|
|||||||
@@ -17,35 +17,34 @@
|
|||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.align-right {
|
||||||
|
text-align: right
|
||||||
|
}
|
||||||
|
|
||||||
.customHeaderMenuButton {
|
.customHeaderMenuButton {
|
||||||
margin-top: 5px;
|
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.customHeaderLabel {
|
.customHeaderLabel {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-top: 3px;
|
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.customSortDownLabel {
|
.customSortDownLabel {
|
||||||
float: left;
|
float: left;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-top: 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.customSortUpLabel {
|
.customSortUpLabel {
|
||||||
float: left;
|
float: left;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
margin-top: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.customSortRemoveLabel {
|
.customSortRemoveLabel {
|
||||||
float: left;
|
float: left;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
margin-top: 6px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
@@ -58,13 +57,11 @@
|
|||||||
|
|
||||||
.customHeaderLabel {
|
.customHeaderLabel {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-top: 3px;
|
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.customExpandButton {
|
.customExpandButton {
|
||||||
float: right;
|
float: right;
|
||||||
margin-top: 5px;
|
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import "../node_modules/bootstrap/dist/css/bootstrap.css";
|
|||||||
|
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
|
// only required when using enterprise features
|
||||||
|
// import {LicenseManager} from "ag-grid-enterprise/main";
|
||||||
|
// LicenseManager.setLicenseKey("<your license key>");
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
render(
|
render(
|
||||||
<App/>,
|
<App/>,
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
.ag-full-width-row .ag-react-container {
|
|
||||||
height: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-width-panel {
|
.full-width-panel {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ export default class DetailPanelComponent extends Component {
|
|||||||
|
|
||||||
this.onGridReady = this.onGridReady.bind(this);
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
this.onSearchTextChange = this.onSearchTextChange.bind(this);
|
this.onSearchTextChange = this.onSearchTextChange.bind(this);
|
||||||
|
|
||||||
|
// override the containing div so that the child grid fills the row height
|
||||||
|
this.props.reactContainer.style.height = "100%";
|
||||||
}
|
}
|
||||||
|
|
||||||
onGridReady(params) {
|
onGridReady(params) {
|
||||||
@@ -41,7 +44,7 @@ export default class DetailPanelComponent extends Component {
|
|||||||
headerName: 'Duration',
|
headerName: 'Duration',
|
||||||
field: 'duration',
|
field: 'duration',
|
||||||
cellClass: 'call-record-cell',
|
cellClass: 'call-record-cell',
|
||||||
cellFormatter: this.secondCellFormatter
|
valueFormatter: this.secondCellFormatter
|
||||||
},
|
},
|
||||||
{headerName: 'Switch', field: 'switchCode', cellClass: 'call-record-cell'}];
|
{headerName: 'Switch', field: 'switchCode', cellClass: 'call-record-cell'}];
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default class MasterDetailExample extends Component {
|
|||||||
},
|
},
|
||||||
{headerName: 'Account', field: 'account'},
|
{headerName: 'Account', field: 'account'},
|
||||||
{headerName: 'Calls', field: 'totalCalls'},
|
{headerName: 'Calls', field: 'totalCalls'},
|
||||||
{headerName: 'Minutes', field: 'totalMinutes', cellFormatter: this.minuteCellFormatter}
|
{headerName: 'Minutes', field: 'totalMinutes', valueFormatter: this.minuteCellFormatter}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,6 @@ export default class MasterDetailExample extends Component {
|
|||||||
|
|
||||||
enableSorting
|
enableSorting
|
||||||
enableColResize
|
enableColResize
|
||||||
suppressMenuFilterPanel
|
|
||||||
|
|
||||||
// events
|
// events
|
||||||
onGridReady={this.onGridReady}>
|
onGridReady={this.onGridReady}>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React, {Component} from "react";
|
|||||||
import {AgGridReact} from "ag-grid-react";
|
import {AgGridReact} from "ag-grid-react";
|
||||||
import StyledRenderer from "./StyledRenderer";
|
import StyledRenderer from "./StyledRenderer";
|
||||||
|
|
||||||
export default class FloatingRowComponentExample extends Component {
|
export default class PinnedRowComponentExample extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -13,8 +13,8 @@ export default class FloatingRowComponentExample extends Component {
|
|||||||
rowData: this.createRowData(),
|
rowData: this.createRowData(),
|
||||||
columnDefs: this.createColumnDefs(),
|
columnDefs: this.createColumnDefs(),
|
||||||
|
|
||||||
topFloatingRowData: [{row: "Top Row", number: "Top Number"}],
|
pinnedTopRowData: [{row: "Top Row", number: "Top Number"}],
|
||||||
bottomFloatingRowData: [{row: "Bottom Row", number: "Bottom Number"}]
|
pinnedBottomRowData: [{row: "Bottom Row", number: "Bottom Number"}]
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onGridReady = this.onGridReady.bind(this);
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
@@ -33,8 +33,8 @@ export default class FloatingRowComponentExample extends Component {
|
|||||||
headerName: "Row",
|
headerName: "Row",
|
||||||
field: "row",
|
field: "row",
|
||||||
width: 400,
|
width: 400,
|
||||||
floatingCellRendererFramework: StyledRenderer,
|
pinnedRowCellRendererFramework: StyledRenderer,
|
||||||
floatingCellRendererParams: {
|
pinnedRowCellRendererParams: {
|
||||||
style: {'fontWeight': 'bold'}
|
style: {'fontWeight': 'bold'}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -42,8 +42,8 @@ export default class FloatingRowComponentExample extends Component {
|
|||||||
headerName: "Number",
|
headerName: "Number",
|
||||||
field: "number",
|
field: "number",
|
||||||
width: 399,
|
width: 399,
|
||||||
floatingCellRendererFramework: StyledRenderer,
|
pinnedRowCellRendererFramework: StyledRenderer,
|
||||||
floatingCellRendererParams: {
|
pinnedRowCellRendererParams: {
|
||||||
style: {'fontStyle': 'italic'}
|
style: {'fontStyle': 'italic'}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -67,14 +67,14 @@ export default class FloatingRowComponentExample extends Component {
|
|||||||
return (
|
return (
|
||||||
<div style={{height: 400, width: 945}}
|
<div style={{height: 400, width: 945}}
|
||||||
className="ag-fresh">
|
className="ag-fresh">
|
||||||
<h1>Floating Row Renderer Example</h1>
|
<h1>Pinned Row Renderer Example</h1>
|
||||||
<AgGridReact
|
<AgGridReact
|
||||||
// properties
|
// properties
|
||||||
columnDefs={this.state.columnDefs}
|
columnDefs={this.state.columnDefs}
|
||||||
rowData={this.state.rowData}
|
rowData={this.state.rowData}
|
||||||
|
|
||||||
floatingTopRowData={this.state.topFloatingRowData}
|
pinnedTopRowData={this.state.pinnedTopRowData}
|
||||||
floatingBottomRowData={this.state.bottomFloatingRowData}
|
pinnedBottomRowData={this.state.pinnedBottomRowData}
|
||||||
|
|
||||||
// events
|
// events
|
||||||
onGridReady={this.onGridReady}>
|
onGridReady={this.onGridReady}>
|
||||||
@@ -4,51 +4,85 @@ import ProficiencyCellRenderer from './ProficiencyCellRenderer.jsx';
|
|||||||
import RefData from './RefData';
|
import RefData from './RefData';
|
||||||
import SkillsFilter from './SkillsFilter.jsx';
|
import SkillsFilter from './SkillsFilter.jsx';
|
||||||
import ProficiencyFilter from './ProficiencyFilter.jsx';
|
import ProficiencyFilter from './ProficiencyFilter.jsx';
|
||||||
import MyReactHeaderGroupComponent from './MyReactHeaderGroupComponent.jsx';
|
import HeaderGroupComponent from './HeaderGroupComponent.jsx';
|
||||||
|
|
||||||
export default class ColDefFactory {
|
export default class ColDefFactory {
|
||||||
|
|
||||||
createColDefs() {
|
createColDefs() {
|
||||||
|
return [
|
||||||
var columnDefs = [
|
{
|
||||||
{headerName: '#', width: 30, checkboxSelection: true, suppressSorting: true,
|
headerName: '#',
|
||||||
suppressMenu: true, pinned: true},
|
width: 30,
|
||||||
|
checkboxSelection: true,
|
||||||
|
suppressSorting: true,
|
||||||
|
suppressMenu: true,
|
||||||
|
pinned: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
headerName: 'Employee',
|
headerName: 'Employee',
|
||||||
headerGroupComponentFramework: MyReactHeaderGroupComponent,
|
headerGroupComponentFramework: HeaderGroupComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
headerName: "Name", field: "name", enableRowGroup: true, enablePivot: true,
|
headerName: "Name",
|
||||||
width: 150, pinned: true, editable: true,
|
field: "name",
|
||||||
|
enableRowGroup: true,
|
||||||
|
enablePivot: true,
|
||||||
|
width: 150,
|
||||||
|
pinned: true,
|
||||||
|
editable: true,
|
||||||
// use a React cellEditor
|
// use a React cellEditor
|
||||||
cellEditorFramework: NameCellEditor
|
cellEditorFramework: NameCellEditor
|
||||||
}, {
|
}, {
|
||||||
headerName: "Country", field: "country", width: 150, enableRowGroup: true, enablePivot: true,
|
headerName: "Country",
|
||||||
|
field: "country",
|
||||||
|
width: 150,
|
||||||
|
enableRowGroup: true,
|
||||||
|
enablePivot: true,
|
||||||
// an example of using a non-React cell renderer
|
// an example of using a non-React cell renderer
|
||||||
cellRenderer: countryCellRenderer, pinned: true,
|
cellRenderer: countryCellRenderer,
|
||||||
|
pinned: true,
|
||||||
filterParams: {
|
filterParams: {
|
||||||
cellRenderer: countryCellRenderer, cellHeight: 20
|
cellRenderer: countryCellRenderer,
|
||||||
}, columnGroupShow: 'open'
|
cellHeight: 20
|
||||||
|
},
|
||||||
|
columnGroupShow: 'open'
|
||||||
}, {
|
}, {
|
||||||
headerName: "DOB", field: "dob", width: 110, enableRowGroup: true, enablePivot: true, filter:'date',
|
headerName: "DOB",
|
||||||
pinned: true, cellRenderer: function(params) {
|
field: "dob",
|
||||||
return pad(params.value.getDate(), 2) + '/' +
|
width: 110,
|
||||||
pad(params.value.getMonth() + 1, 2)+ '/' +
|
enableRowGroup: true,
|
||||||
params.value.getFullYear();
|
enablePivot: true,
|
||||||
}, columnGroupShow: 'open'
|
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',
|
headerName: 'IT Skills',
|
||||||
children: [
|
children: [
|
||||||
{headerName: "Skills", width: 125, suppressSorting: true, field: 'skills', enableRowGroup: true, enablePivot: true,
|
{
|
||||||
|
headerName: "Skills",
|
||||||
|
width: 125,
|
||||||
|
suppressSorting: true,
|
||||||
|
field: 'skills',
|
||||||
|
enableRowGroup: true,
|
||||||
|
enablePivot: true,
|
||||||
// supply a React component
|
// supply a React component
|
||||||
cellRendererFramework: SkillsCellRenderer,
|
cellRendererFramework: SkillsCellRenderer,
|
||||||
// supply a React component
|
// supply a React component
|
||||||
filterFramework: SkillsFilter
|
filterFramework: SkillsFilter
|
||||||
},
|
},
|
||||||
{headerName: "Proficiency", field: "proficiency", width: 135, enableValue: true,
|
{
|
||||||
|
headerName: "Proficiency",
|
||||||
|
field: "proficiency",
|
||||||
|
width: 135,
|
||||||
|
enableValue: true,
|
||||||
// supply a React component
|
// supply a React component
|
||||||
cellRendererFramework: ProficiencyCellRenderer,
|
cellRendererFramework: ProficiencyCellRenderer,
|
||||||
// supply a React component
|
// supply a React component
|
||||||
@@ -65,7 +99,6 @@ export default class ColDefFactory {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
return columnDefs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +106,7 @@ export default class ColDefFactory {
|
|||||||
// need to use React for it.
|
// need to use React for it.
|
||||||
function countryCellRenderer(params) {
|
function countryCellRenderer(params) {
|
||||||
if (params.value) {
|
if (params.value) {
|
||||||
var flag = "<img border='0' width='15' height='10' " +
|
const flag = "<img border='0' width='15' height='10' " +
|
||||||
"style='margin-bottom: 2px' src='http://flags.fmcdn.net/data/flags/mini/"
|
"style='margin-bottom: 2px' src='http://flags.fmcdn.net/data/flags/mini/"
|
||||||
+ RefData.COUNTRY_CODES[params.value] + ".png'>";
|
+ RefData.COUNTRY_CODES[params.value] + ".png'>";
|
||||||
return flag + " " + params.value;
|
return flag + " " + params.value;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
|
import * as PropTypes from "prop-types";
|
||||||
|
|
||||||
// Date Component to be used in the date filter.
|
// 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
|
// 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
|
// 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.
|
// getDate and setDate and that it calls back into props.onDateChanged every time that the date changes.
|
||||||
export default class MyReactDateComponent extends React.Component {
|
export default class DateComponent extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -27,7 +28,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
//Inlining styles to make simpler the component
|
//Inlining styles to make simpler the component
|
||||||
let filterStyle = {
|
let filterStyle = {
|
||||||
margin:'2px'
|
margin: '2px'
|
||||||
};
|
};
|
||||||
let ddStyle = {
|
let ddStyle = {
|
||||||
width: '30px'
|
width: '30px'
|
||||||
@@ -50,9 +51,12 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div style={filterStyle}>
|
<div style={filterStyle}>
|
||||||
<span style={resetStyle} onClick={this.resetDate.bind(this)}>x</span>
|
<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="dd" placeholder="dd" style={ddStyle}
|
||||||
<input onInput = {this.onDateChanged.bind(this)} ref="mm" placeholder="mm" style={mmStyle} value={this.state.textBoxes.mm} maxLength="2"/>/
|
value={this.state.textBoxes.dd} maxLength="2"/>/
|
||||||
<input onInput = {this.onDateChanged.bind(this)} ref="yyyy" placeholder="yyyy" style={yyyyStyle} value={this.state.textBoxes.yyyy} maxLength="4"/>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -61,20 +65,20 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// METHODS REQUIRED BY AG-GRID
|
// METHODS REQUIRED BY AG-GRID
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
getDate (){
|
getDate() {
|
||||||
//ag-grid will call us here when in need to check what the current date value is hold by this
|
//ag-grid will call us here when in need to check what the current date value is hold by this
|
||||||
//component.
|
//component.
|
||||||
return this.state.date;
|
return this.state.date;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDate (date){
|
setDate(date) {
|
||||||
//ag-grid will call us here when it needs this component to update the date that it holds.
|
//ag-grid will call us here when it needs this component to update the date that it holds.
|
||||||
this.setState({
|
this.setState({
|
||||||
date:date,
|
date,
|
||||||
textBoxes:{
|
textBoxes: {
|
||||||
dd: date.getDate(),
|
dd: date ? date.getDate() : '',
|
||||||
mm: date.getMonth() + 1,
|
mm: date ? date.getMonth() + 1 : '',
|
||||||
yyyy: date.getFullYear()
|
yyyy: date ? date.getFullYear() : ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -83,10 +87,10 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// LINKS THE INTERNAL STATE AND AG-GRID
|
// LINKS THE INTERNAL STATE AND AG-GRID
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
updateAndNotifyAgGrid (date, textBoxes){
|
updateAndNotifyAgGrid(date, textBoxes) {
|
||||||
this.setState ({
|
this.setState({
|
||||||
date: date,
|
date: date,
|
||||||
textBoxes:textBoxes
|
textBoxes: textBoxes
|
||||||
},
|
},
|
||||||
//Callback after the state is set. This is where we tell ag-grid that the date has changed so
|
//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
|
//it will proceed with the filtering and we can then expect ag-Grid to call us back to getDate
|
||||||
@@ -99,23 +103,23 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// LINKING THE UI, THE STATE AND AG-GRID
|
// LINKING THE UI, THE STATE AND AG-GRID
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
resetDate (){
|
resetDate() {
|
||||||
let date = null;
|
let date = null;
|
||||||
let textBoxes = {
|
let textBoxes = {
|
||||||
dd : '',
|
dd: '',
|
||||||
mm : '',
|
mm: '',
|
||||||
yyyy : '',
|
yyyy: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateAndNotifyAgGrid(date, textBoxes)
|
this.updateAndNotifyAgGrid(date, textBoxes)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDateChanged () {
|
onDateChanged() {
|
||||||
let date = this.parseDate(this.refs.dd.value, this.refs.mm.value, this.refs.yyyy.value);
|
let date = this.parseDate(this.refs.dd.value, this.refs.mm.value, this.refs.yyyy.value);
|
||||||
let textBoxes = {
|
let textBoxes = {
|
||||||
dd : this.refs.dd.value,
|
dd: this.refs.dd.value,
|
||||||
mm : this.refs.mm.value,
|
mm: this.refs.mm.value,
|
||||||
yyyy : this.refs.yyyy.value,
|
yyyy: this.refs.yyyy.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateAndNotifyAgGrid(date, textBoxes)
|
this.updateAndNotifyAgGrid(date, textBoxes)
|
||||||
@@ -125,7 +129,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// INTERNAL LOGIC
|
// INTERNAL LOGIC
|
||||||
//*********************************************************************************
|
//*********************************************************************************
|
||||||
|
|
||||||
parseDate (dd, mm, yyyy){
|
parseDate(dd, mm, yyyy) {
|
||||||
//If any of the three input date fields are empty, stop and return null
|
//If any of the three input date fields are empty, stop and return null
|
||||||
if (dd.trim() === '' || mm.trim() === '' || yyyy.trim() === '') {
|
if (dd.trim() === '' || mm.trim() === '' || yyyy.trim() === '') {
|
||||||
return null;
|
return null;
|
||||||
@@ -138,7 +142,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
let date = new Date(year, month - 1, day);
|
let date = new Date(year, month - 1, day);
|
||||||
|
|
||||||
//If the date is not valid
|
//If the date is not valid
|
||||||
if (isNaN(date.getTime())){
|
if (isNaN(date.getTime())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +154,7 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
//If the javascript date parts don't match the provided fields, we assume that the input is non
|
//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
|
//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
|
//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){
|
if (date.getDate() != day || date.getMonth() + 1 != month || date.getFullYear() != year) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +166,6 @@ export default class MyReactDateComponent extends React.Component {
|
|||||||
// which is the grid passing you the params for the cellRenderer.
|
// which is the grid passing you the params for the cellRenderer.
|
||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
MyReactDateComponent.propTypes = {
|
DateComponent.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
// Header component to be used as default for all the columns.
|
// Header component to be used as default for all the columns.
|
||||||
export default class MyReactHeaderGroupComponent extends React.Component {
|
export default class HeaderGroupComponent extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.props.columnGroup.getOriginalColumnGroup().addEventListener('expandedChanged', this.onExpandChanged.bind(this));
|
this.props.columnGroup.getOriginalColumnGroup().addEventListener('expandedChanged', this.onExpandChanged.bind(this));
|
||||||
this.state = {
|
this.state = {
|
||||||
expanded:null
|
expanded: null
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
this.onExpandChanged();
|
this.onExpandChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +40,6 @@ export default class MyReactHeaderGroupComponent extends React.Component {
|
|||||||
// which is the grid passing you the params for the cellRenderer.
|
// which is the grid passing you the params for the cellRenderer.
|
||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
MyReactHeaderGroupComponent.propTypes = {
|
HeaderGroupComponent.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
// Header component to be used as default for all the columns.
|
|
||||||
export default class MyReactHeaderComponent extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.props.column.addEventListener('sortChanged', this.onSortChanged.bind(this));
|
|
||||||
|
|
||||||
//The state of this component contains the current sort state of this column
|
|
||||||
//The possible values are: 'asc', 'desc' and ''
|
|
||||||
this.state = {
|
|
||||||
sorted: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 className={downArrowClass} onClick={this.onSortRequested.bind(this, 'desc')}><i className="fa fa-long-arrow-down"/></div>)
|
|
||||||
sortElements.push(<div className={upArrowClass} onClick={this.onSortRequested.bind(this, 'asc')}><i className="fa fa-long-arrow-up"/></div>)
|
|
||||||
sortElements.push(<div 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.
|
|
||||||
MyReactHeaderComponent.propTypes = {
|
|
||||||
params: React.PropTypes.object
|
|
||||||
};
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import RefData from './RefData';
|
import RefData from './RefData';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
|
|
||||||
var KEY_BACKSPACE = 8;
|
var KEY_BACKSPACE = 8;
|
||||||
var KEY_DELETE = 46;
|
var KEY_DELETE = 46;
|
||||||
@@ -113,5 +114,5 @@ export default class NameCellEditor extends React.Component {
|
|||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
NameCellEditor.propTypes = {
|
NameCellEditor.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -32,11 +32,9 @@ export default class ProficiencyFilter extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onButtonPressed(name) {
|
onButtonPressed(name) {
|
||||||
console.log(name);
|
|
||||||
var newState = {selected: name};
|
var newState = {selected: name};
|
||||||
// set the state, and once it is done, then call filterChangedCallback
|
// set the state, and once it is done, then call filterChangedCallback
|
||||||
this.setState(newState, this.props.filterChangedCallback);
|
this.setState(newState, this.props.filterChangedCallback);
|
||||||
console.log(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
.ag-react-container {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ag-cell {
|
.ag-cell {
|
||||||
padding-top: 2px !important;
|
padding-top: 2px !important;
|
||||||
padding-bottom: 2px !important;
|
padding-bottom: 2px !important;
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import React, {Component} from "react";
|
|||||||
import {AgGridReact} from "ag-grid-react";
|
import {AgGridReact} from "ag-grid-react";
|
||||||
import RowDataFactory from "./RowDataFactory";
|
import RowDataFactory from "./RowDataFactory";
|
||||||
import ColDefFactory from "./ColDefFactory.jsx";
|
import ColDefFactory from "./ColDefFactory.jsx";
|
||||||
import MyReactDateComponent from "./MyReactDateComponent.jsx";
|
import DateComponent from "./DateComponent.jsx";
|
||||||
import MyReactHeaderComponent from "./MyReactHeaderComponent.jsx";
|
import SortableHeaderComponent from "./SortableHeaderComponent";
|
||||||
|
|
||||||
import "./RichGridExample.css";
|
import "./RichGridExample.css";
|
||||||
|
|
||||||
// take this line out if you do not want to use ag-Grid-Enterprise
|
// take this line out if you do not want to use ag-Grid-Enterprise
|
||||||
import "ag-grid-enterprise";
|
import "ag-grid-enterprise";
|
||||||
|
|
||||||
@@ -29,7 +28,10 @@ export default class RichGridExample extends Component {
|
|||||||
groupExpanded: '<i class="fa fa-minus-square-o"/>',
|
groupExpanded: '<i class="fa fa-minus-square-o"/>',
|
||||||
groupContracted: '<i class="fa fa-plus-square-o"/>',
|
groupContracted: '<i class="fa fa-plus-square-o"/>',
|
||||||
columnGroupOpened: '<i class="fa fa-minus-square-o"/>',
|
columnGroupOpened: '<i class="fa fa-minus-square-o"/>',
|
||||||
columnGroupClosed: '<i class="fa fa-plus-square-o"/>'
|
columnGroupClosed: '<i class="fa fa-plus-square-o"/>',
|
||||||
|
checkboxChecked: '<i class="fa fa-arrow-left"/>',
|
||||||
|
checkboxUnchecked: '<i class="fa fa-arrow-right"/>',
|
||||||
|
checkboxIndeterminate: '<i class="fa fa-arrow-up"/>'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,13 +43,13 @@ export default class RichGridExample extends Component {
|
|||||||
// what you want!
|
// what you want!
|
||||||
this.gridOptions = {
|
this.gridOptions = {
|
||||||
//We register the react date component that ag-grid will use to render
|
//We register the react date component that ag-grid will use to render
|
||||||
dateComponentFramework: MyReactDateComponent,
|
dateComponentFramework: DateComponent,
|
||||||
// this is how you listen for events using gridOptions
|
// this is how you listen for events using gridOptions
|
||||||
onModelUpdated: function () {
|
onModelUpdated: function () {
|
||||||
console.log('event onModelUpdated received');
|
console.log('event onModelUpdated received');
|
||||||
},
|
},
|
||||||
defaultColDef: {
|
defaultColDef: {
|
||||||
headerComponentFramework: MyReactHeaderComponent,
|
headerComponentFramework: SortableHeaderComponent,
|
||||||
headerComponentParams: {
|
headerComponentParams: {
|
||||||
menuIcon: 'fa-bars'
|
menuIcon: 'fa-bars'
|
||||||
}
|
}
|
||||||
@@ -76,10 +78,6 @@ export default class RichGridExample extends Component {
|
|||||||
this.columnApi = params.columnApi;
|
this.columnApi = params.columnApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectAll() {
|
|
||||||
this.api.selectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
deselectAll() {
|
deselectAll() {
|
||||||
this.api.deselectAll();
|
this.api.deselectAll();
|
||||||
}
|
}
|
||||||
@@ -101,15 +99,15 @@ export default class RichGridExample extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRefreshData() {
|
onRefreshData() {
|
||||||
var newRowData = new RowDataFactory().createRowData();
|
let newRowData = new RowDataFactory().createRowData();
|
||||||
this.setState({
|
this.setState({
|
||||||
rowData: newRowData
|
rowData: newRowData
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeSkillsFilterMethod() {
|
invokeSkillsFilterMethod() {
|
||||||
var skillsFilter = this.api.getFilterInstance('skills');
|
let skillsFilter = this.api.getFilterInstance('skills');
|
||||||
var componentInstance = skillsFilter.getFrameworkComponentInstance();
|
let componentInstance = skillsFilter.getFrameworkComponentInstance();
|
||||||
componentInstance.helloFromSkillsFilter();
|
componentInstance.helloFromSkillsFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,14 +115,19 @@ export default class RichGridExample extends Component {
|
|||||||
let dateFilterComponent = this.gridOptions.api.getFilterInstance('dob');
|
let dateFilterComponent = this.gridOptions.api.getFilterInstance('dob');
|
||||||
dateFilterComponent.setFilterType('equals');
|
dateFilterComponent.setFilterType('equals');
|
||||||
dateFilterComponent.setDateFrom('2000-01-01');
|
dateFilterComponent.setDateFrom('2000-01-01');
|
||||||
this.gridOptions.api.onFilterChanged();
|
|
||||||
|
|
||||||
|
// 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.gridOptions.api.onFilterChanged();
|
||||||
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var gridTemplate;
|
let gridTemplate;
|
||||||
var bottomHeaderTemplate;
|
let bottomHeaderTemplate;
|
||||||
var topHeaderTemplate;
|
let topHeaderTemplate;
|
||||||
|
|
||||||
topHeaderTemplate = (
|
topHeaderTemplate = (
|
||||||
<div>
|
<div>
|
||||||
@@ -151,7 +154,10 @@ export default class RichGridExample extends Component {
|
|||||||
<div style={{padding: 4}} className={'toolbar'}>
|
<div style={{padding: 4}} className={'toolbar'}>
|
||||||
<span>
|
<span>
|
||||||
Grid API:
|
Grid API:
|
||||||
<button onClick={this.selectAll.bind(this)}>Select All</button>
|
{/* use ref to access the api in selectAll */}
|
||||||
|
<button onClick={() => {
|
||||||
|
this.refs.myGrid.api.selectAll()
|
||||||
|
}}>Select All</button>
|
||||||
<button onClick={this.deselectAll.bind(this)}>Clear Selection</button>
|
<button onClick={this.deselectAll.bind(this)}>Clear Selection</button>
|
||||||
</span>
|
</span>
|
||||||
<span style={{marginLeft: 20}}>
|
<span style={{marginLeft: 20}}>
|
||||||
@@ -181,6 +187,7 @@ export default class RichGridExample extends Component {
|
|||||||
gridTemplate = (
|
gridTemplate = (
|
||||||
<div style={{height: 400, width: 945}} className="ag-fresh">
|
<div style={{height: 400, width: 945}} className="ag-fresh">
|
||||||
<AgGridReact
|
<AgGridReact
|
||||||
|
ref="myGrid"
|
||||||
// gridOptions is optional - it's possible to provide
|
// gridOptions is optional - it's possible to provide
|
||||||
// all values as React props
|
// all values as React props
|
||||||
gridOptions={this.gridOptions}
|
gridOptions={this.gridOptions}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import * as PropTypes from 'prop-types';
|
||||||
import RefData from './RefData';
|
import RefData from './RefData';
|
||||||
|
|
||||||
export default class SkillsCellRenderer extends React.Component {
|
export default class SkillsCellRenderer extends React.Component {
|
||||||
@@ -22,5 +23,5 @@ export default class SkillsCellRenderer extends React.Component {
|
|||||||
// this piece is optional. the grid will always pass the 'params'
|
// this piece is optional. the grid will always pass the 'params'
|
||||||
// props, so little need for adding this validation meta-data.
|
// props, so little need for adding this validation meta-data.
|
||||||
SkillsCellRenderer.propTypes = {
|
SkillsCellRenderer.propTypes = {
|
||||||
params: React.PropTypes.object
|
params: PropTypes.object
|
||||||
};
|
};
|
||||||
@@ -31,11 +31,11 @@ export default class SkillsFilter extends React.Component {
|
|||||||
|
|
||||||
setModel(model) {
|
setModel(model) {
|
||||||
this.setState({
|
this.setState({
|
||||||
android: model.android,
|
android: model ? model.android : null,
|
||||||
css: model.css,
|
css: model ? model.css : null,
|
||||||
html5: model.html5,
|
html5: model ? model.html5 : null,
|
||||||
mac: model.mac,
|
mac: model ? model.mac : null,
|
||||||
windows: model.windows
|
windows: model ? model.windows : null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
86
src/richGridExample/SortableHeaderComponent.jsx
Normal file
86
src/richGridExample/SortableHeaderComponent.jsx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
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
|
||||||
|
};
|
||||||
57
src/simpleReduxDynamicComponentExample/GridComponent.jsx
Normal file
57
src/simpleReduxDynamicComponentExample/GridComponent.jsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
|
||||||
|
import {AgGridReact} from "ag-grid-react";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
|
import PriceRenderer from "./PriceRenderer";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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', cellClass: 'align-right', cellRendererFramework: PriceRenderer}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onGridReady = this.onGridReady.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onGridReady(params) {
|
||||||
|
this.gridApi = params.api;
|
||||||
|
this.columnApi = params.columnApi;
|
||||||
|
|
||||||
|
this.gridApi.sizeColumnsToFit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// row data will be provided via redux on this.props.rowData
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{height: 400, width: 945, marginTop: 15}}
|
||||||
|
className="ag-fresh">
|
||||||
|
<AgGridReact
|
||||||
|
// properties
|
||||||
|
columnDefs={this.state.columnDefs}
|
||||||
|
rowData={this.props.rowData}
|
||||||
|
|
||||||
|
// events
|
||||||
|
onGridReady={this.onGridReady}>
|
||||||
|
</AgGridReact>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull off row data changes
|
||||||
|
export default connect(
|
||||||
|
(state) => {
|
||||||
|
return {
|
||||||
|
rowData: state.rowData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(GridComponent);
|
||||||
85
src/simpleReduxDynamicComponentExample/HeaderComponent.jsx
Normal file
85
src/simpleReduxDynamicComponentExample/HeaderComponent.jsx
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
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 {setCurrency, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// provide the initial data to the store (which in turn will populate the grid)
|
||||||
|
this.props.dispatch(updateRowData(this.createRowData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrency(currencySymbol, exchangeRate) {
|
||||||
|
this.props.dispatch(setCurrency(currencySymbol, exchangeRate));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div style={{marginTop: 15}}>
|
||||||
|
<button onClick={this.setCurrency.bind(this, '£', 1)}>Set Currency to GBP</button>
|
||||||
|
<button onClick={this.setCurrency.bind(this, '$', 1.29)}>Set Currency to USD</button>
|
||||||
|
</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 {
|
||||||
|
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
|
||||||
|
export default connect(
|
||||||
|
(state) => {
|
||||||
|
return {
|
||||||
|
rowData: state.rowData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(HeaderComponent);
|
||||||
37
src/simpleReduxDynamicComponentExample/PriceRenderer.jsx
Normal file
37
src/simpleReduxDynamicComponentExample/PriceRenderer.jsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
|
class PriceRenderer extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
convertedValue: this.applyExchangeRate(props.exchangeRate, props.value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
this.setState({
|
||||||
|
convertedValue: this.applyExchangeRate(nextProps.exchangeRate, nextProps.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<span>{this.props.currencySymbol}{this.state.convertedValue}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyExchangeRate = (exchangeRate, value) => {
|
||||||
|
return parseFloat(value * exchangeRate).toFixed(2); // simplified/naive exchange rate implementation!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
(state) => {
|
||||||
|
return {
|
||||||
|
currencySymbol: state.currencySymbol,
|
||||||
|
exchangeRate: state.exchangeRate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)(PriceRenderer);
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Provider store={store}>
|
||||||
|
<div>
|
||||||
|
<h1>Simple Redux Example using Connected React Components</h1>
|
||||||
|
<HeaderComponent />
|
||||||
|
<GridComponent />
|
||||||
|
</div>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
13
src/simpleReduxDynamicComponentExample/gridDataActions.jsx
Normal file
13
src/simpleReduxDynamicComponentExample/gridDataActions.jsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export function updateRowData(rowData) {
|
||||||
|
return {
|
||||||
|
type: 'ROW_DATA_CHANGED',
|
||||||
|
rowData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function setCurrency(currencySymbol, exchangeRate) {
|
||||||
|
return {
|
||||||
|
type: 'CURRENCY_CHANGED',
|
||||||
|
currencySymbol,
|
||||||
|
exchangeRate
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/simpleReduxDynamicComponentExample/gridDataReducer.jsx
Normal file
17
src/simpleReduxDynamicComponentExample/gridDataReducer.jsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export default (state = {rowData: [], currencySymbol: '£', exchangeRate: 1}, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'ROW_DATA_CHANGED':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
rowData: action.rowData,
|
||||||
|
};
|
||||||
|
case 'CURRENCY_CHANGED':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
currencySymbol: action.currencySymbol,
|
||||||
|
exchangeRate: action.exchangeRate
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -75,7 +75,7 @@ class GridComponent extends Component {
|
|||||||
enableColResize
|
enableColResize
|
||||||
rowSelection="multiple"
|
rowSelection="multiple"
|
||||||
enableRangeSelection
|
enableRangeSelection
|
||||||
groupColumnDef={{
|
autoColumnGroupDef={{
|
||||||
headerName: 'Symbol',
|
headerName: 'Symbol',
|
||||||
cellRenderer: 'group',
|
cellRenderer: 'group',
|
||||||
field: 'symbol'
|
field: 'symbol'
|
||||||
|
|||||||
Reference in New Issue
Block a user