diff --git a/src/App.jsx b/src/App.jsx index aec68c2..7c88682 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -13,6 +13,7 @@ import FilterComponentExample from "./filterComponentExample/FilterComponentExam import MasterDetailExample from "./masterDetailExample/MasterDetailExample"; import SimpleReduxExample from "./simpleReduxExample/SimpleReduxExample"; import FloatingFilterGridExample from "./floatingFilter/FloatingFilterGridExample"; +import SimpleReduxDynamicExample from "./simpleReduxDynamicComponentExample/SimpleReduxExample"; class App extends Component { constructor(props) { @@ -52,6 +53,7 @@ class App extends Component {
  • this.setExample("floating-filter")}>Floating Filters
  • this.setExample("master-detail")}>Master Detail Example
  • this.setExample("simple-redux")}>Simple Redux Example
  • +
  • this.setExample("simple-redux-dynamic")}>Simple Redux Dynamic Component Example
  • ) } @@ -87,6 +89,9 @@ class App extends Component { case 'floating-filter': example = ; break; + case 'simple-redux-dynamic': + example = ; + break; default: example = ; } diff --git a/src/index.html b/src/index.html index 51914d1..ad6bb91 100644 --- a/src/index.html +++ b/src/index.html @@ -17,6 +17,10 @@ margin-right: 4px; } + .align-right { + text-align: right + } + .customHeaderMenuButton { margin-left: 4px; float: left; diff --git a/src/simpleReduxDynamicComponentExample/GridComponent.jsx b/src/simpleReduxDynamicComponentExample/GridComponent.jsx new file mode 100644 index 0000000..14cc59b --- /dev/null +++ b/src/simpleReduxDynamicComponentExample/GridComponent.jsx @@ -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 ( +
    + + +
    + ) + } +} + +// pull off row data changes +export default connect( + (state) => { + return { + rowData: state.rowData + } + } +)(GridComponent); \ No newline at end of file diff --git a/src/simpleReduxDynamicComponentExample/HeaderComponent.jsx b/src/simpleReduxDynamicComponentExample/HeaderComponent.jsx new file mode 100644 index 0000000..6c3b80a --- /dev/null +++ b/src/simpleReduxDynamicComponentExample/HeaderComponent.jsx @@ -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 ( +
    + + +
    + ) + } + + // 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); \ No newline at end of file diff --git a/src/simpleReduxDynamicComponentExample/PriceRenderer.jsx b/src/simpleReduxDynamicComponentExample/PriceRenderer.jsx new file mode 100644 index 0000000..92bd9dd --- /dev/null +++ b/src/simpleReduxDynamicComponentExample/PriceRenderer.jsx @@ -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 ( + {this.props.currencySymbol}{this.state.convertedValue} + ); + } + + 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); \ No newline at end of file diff --git a/src/simpleReduxDynamicComponentExample/SimpleReduxExample.jsx b/src/simpleReduxDynamicComponentExample/SimpleReduxExample.jsx new file mode 100644 index 0000000..9050407 --- /dev/null +++ b/src/simpleReduxDynamicComponentExample/SimpleReduxExample.jsx @@ -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 ( + +
    +

    Simple Redux Example using Connected React Components

    + + +
    +
    + ) + } +}; diff --git a/src/simpleReduxDynamicComponentExample/gridDataActions.jsx b/src/simpleReduxDynamicComponentExample/gridDataActions.jsx new file mode 100644 index 0000000..fea6f2d --- /dev/null +++ b/src/simpleReduxDynamicComponentExample/gridDataActions.jsx @@ -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 + } +} \ No newline at end of file diff --git a/src/simpleReduxDynamicComponentExample/gridDataReducer.jsx b/src/simpleReduxDynamicComponentExample/gridDataReducer.jsx new file mode 100644 index 0000000..229be5b --- /dev/null +++ b/src/simpleReduxDynamicComponentExample/gridDataReducer.jsx @@ -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; + } +}; \ No newline at end of file