Compare commits

...

5 Commits

Author SHA1 Message Date
Alberto
f8f0c21af2 Version 11.0.0 2017-06-26 16:40:27 +02:00
Sean Landsman
b54d549959 AG-528 Document and use in examples overriding of style in child (react component) divs 2017-06-14 15:32:09 +01:00
Sean Landsman
464a0ea9f4 AG-529 Implement improvements - esp around property changes 2017-06-14 13:15:54 +01:00
Sean Landsman
675cbe497c AG-538 Upgrade to React 15x
AG-539 React rich grid example - fix bugs
2017-06-13 18:15:05 +01:00
Sean Landsman
a4dbbf529d AG-534 Make use of new data retrieval & updating in trader dashboard 2017-06-13 15:17:30 +01:00
26 changed files with 168 additions and 153 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "ag-grid-react-example", "name": "ag-grid-react-example",
"version": "10.0.0", "version": "11.0.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": {
@@ -17,7 +17,8 @@
"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/react-examples/examples && ncp dist/trader ../ag-grid-docs/src/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",
@@ -42,6 +43,7 @@
"babel-preset-react": "6.24.x", "babel-preset-react": "6.24.x",
"babel-preset-stage-0": "6.24.x", "babel-preset-stage-0": "6.24.x",
"babel-preset-stage-1": "6.24.x", "babel-preset-stage-1": "6.24.x",
"prop-types": "15.5.x",
"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",
@@ -60,9 +62,9 @@
"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": "11.0.x",
"ag-grid-enterprise": "10.1.x", "ag-grid-enterprise": "11.0.x",
"ag-grid-react": "10.1.x" "ag-grid-react": "11.0.x"
} }
} }

View File

@@ -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
}; };

View File

@@ -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>

View File

@@ -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";
@@ -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}>

View File

@@ -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);
} }

View File

@@ -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
}; };

View File

@@ -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) {

View File

@@ -30,7 +30,6 @@ class App extends Component {
} }
setExample(example) { setExample(example) {
console.log(example);
this.setState({ this.setState({
example example
}) })

View File

@@ -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}>

View File

@@ -1,3 +0,0 @@
.ag-group-value .ag-react-container {
display: inline-block;
}

View File

@@ -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 {

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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'}];

View File

@@ -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}>

View File

@@ -4,7 +4,7 @@ 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 {
@@ -15,7 +15,7 @@ export default class ColDefFactory {
suppressMenu: true, pinned: 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", field: "name", enableRowGroup: true, enablePivot: true,

View File

@@ -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
}; };

View File

@@ -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
}; };

View File

@@ -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
}; };

View File

@@ -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() {

View File

@@ -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;

View File

@@ -2,8 +2,8 @@ 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";
@@ -41,13 +41,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'
} }
@@ -101,15 +101,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 +117,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>

View File

@@ -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
}; };

View File

@@ -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
}); });
} }

View File

@@ -1,7 +1,8 @@
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 MyReactHeaderComponent extends React.Component { export default class SortableHeaderComponent extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -11,27 +12,32 @@ export default class MyReactHeaderComponent extends React.Component {
//The state of this component contains the current sort state of this column //The state of this component contains the current sort state of this column
//The possible values are: 'asc', 'desc' and '' //The possible values are: 'asc', 'desc' and ''
this.state = { this.state = {
sorted: '' sorted: ''
} }
} }
render() { render() {
let sortElements = []; let sortElements = [];
if (this.props.enableSorting){ if (this.props.enableSorting) {
let downArrowClass = "customSortDownLabel " + (this.state.sorted === 'desc' ? " active" : ""); let downArrowClass = "customSortDownLabel " + (this.state.sorted === 'desc' ? " active" : "");
let upArrowClass = "customSortUpLabel " + (this.state.sorted === 'asc' ? " active" : ""); let upArrowClass = "customSortUpLabel " + (this.state.sorted === 'asc' ? " active" : "");
let removeArrowClass = "customSortRemoveLabel " + (this.state.sorted === '' ? " 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 key={`up${this.props.displayName}`} className={downArrowClass} onClick={this.onSortRequested.bind(this, 'desc')}><i
sortElements.push(<div className={upArrowClass} onClick={this.onSortRequested.bind(this, 'asc')}><i className="fa fa-long-arrow-up"/></div>) className="fa fa-long-arrow-down"/></div>)
sortElements.push(<div className={removeArrowClass} onClick={this.onSortRequested.bind(this, '')}><i className="fa fa-times"/></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; let menuButton = null;
if (this.props.enableMenu){ if (this.props.enableMenu) {
menuButton = <div ref="menuButton" className="customHeaderMenuButton" onClick={this.onMenuClick.bind(this)}><i className={"fa " + this.props.menuIcon}/></div> menuButton =
<div ref="menuButton" className="customHeaderMenuButton" onClick={this.onMenuClick.bind(this)}><i
className={"fa " + this.props.menuIcon}/></div>
} }
return <div> return <div>
@@ -41,16 +47,16 @@ export default class MyReactHeaderComponent extends React.Component {
</div> </div>
} }
onSortRequested (order, event) { onSortRequested(order, event) {
this.props.setSort (order, event.shiftKey); this.props.setSort(order, event.shiftKey);
}; };
onSortChanged (){ onSortChanged() {
if (this.props.column.isSortAscending()){ if (this.props.column.isSortAscending()) {
this.setState({ this.setState({
sorted: 'asc' sorted: 'asc'
}) })
} else if (this.props.column.isSortDescending()){ } else if (this.props.column.isSortDescending()) {
this.setState({ this.setState({
sorted: 'desc' sorted: 'desc'
}) })
@@ -61,8 +67,8 @@ export default class MyReactHeaderComponent extends React.Component {
} }
}; };
onMenuClick (){ onMenuClick() {
this.props.showColumnMenu (this.refs.menuButton); this.props.showColumnMenu(this.refs.menuButton);
}; };
} }
@@ -71,6 +77,6 @@ export default class MyReactHeaderComponent 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.
MyReactHeaderComponent.propTypes = { SortableHeaderComponent.propTypes = {
params: React.PropTypes.object params: PropTypes.object
}; };

View File

@@ -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'