Compare commits

...

10 Commits
7.1.1 ... ag140

14 changed files with 9055 additions and 19 deletions

8618
olympicWinners.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,11 @@
{
"name": "ag-grid-react-example",
"version": "7.1.1",
"version": "7.2.0",
"description": "Example Reach applicaiton using ag-Grid.",
"main": "dist/ag-grid-react-example.js",
"scripts": {
"standard": "webpack-dev-server --config webpack.config.standard.js --progress --colors --hot --inline",
"grouped": "webpack-dev-server --config webpack.config.grouped.js --progress --colors --hot --inline",
"large": "webpack-dev-server --config webpack.config.large.js --progress --colors --hot --inline"
},
"repository": {
@@ -36,8 +37,8 @@
"dependencies": {
"react": "0.14.6",
"react-dom": "0.14.6",
"ag-grid": "7.1.x",
"ag-grid-enterprise": "7.1.x",
"ag-grid-react": "7.1.x"
"ag-grid": "7.2.x",
"ag-grid-enterprise": "7.2.x",
"ag-grid-react": "7.2.x"
}
}

View File

@@ -0,0 +1,17 @@
export default class ColDefFactory {
createColDefs() {
return [
{headerName: "Athlete", field: "athlete", width: 200},
{headerName: "Age", field: "age", width: 90},
{headerName: "Gold", field: "gold", width: 100, aggFunc: 'sum'},
{headerName: "Silver", field: "silver", width: 100, aggFunc: 'sum'},
{headerName: "Bronze", field: "bronze", width: 100, aggFunc: 'sum'},
{headerName: "Total", field: "total", width: 100, aggFunc: 'sum'},
{headerName: "Country", field: "country", width: 120, rowGroupIndex: 0},
{headerName: "Year", field: "year", width: 90},
{headerName: "Date", field: "date", width: 110},
{headerName: "Sport", field: "sport", width: 110}
];
}
}

18
src-grouped/index.js Normal file
View File

@@ -0,0 +1,18 @@
'use strict';
import ReactDOM from 'react-dom';
import React from 'react';
import MyApp from './myApp.jsx';
// is there a better way of doing this?
import 'ag-grid-root/dist/styles/ag-grid.css';
import 'ag-grid-root/dist/styles/theme-fresh.css';
// waiting for dom to load before booting react. we could alternatively
// put the index.js reference at the end fo the index.html, but i prefer this way.
document.addEventListener('DOMContentLoaded', ()=> {
var container = document.getElementById('myAppContainer');
ReactDOM.render(
React.createElement(MyApp),
container
);
});

28
src-grouped/myApp.css Normal file
View File

@@ -0,0 +1,28 @@
.ag-cell {
padding-top: 2px !important;
padding-bottom: 2px !important;
}
label {
font-weight: normal !important;
}
.div-percent-bar {
display: inline-block;
height: 20px;
position: relative;
}
.div-percent-value {
position: absolute;
padding-left: 4px;
font-weight: bold;
font-size: 13px;
}
.div-outer-div {
display: inline-block;
height: 100%;
width: 100%;
}

99
src-grouped/myApp.jsx Normal file
View File

@@ -0,0 +1,99 @@
import React from "react";
import {AgGridReact} from "ag-grid-react";
import ColDefFactory from "./ColDefFactory.jsx";
import "./myApp.css";
// take this line out if you do not want to use ag-Grid-Enterprise
import "ag-grid-enterprise";
export default class MyApp extends React.Component {
constructor() {
super();
this.state = {
showToolPanel: false,
columnDefs: new ColDefFactory().createColDefs(),
rowData: null,
};
this.gridOptions = {
groupRowInnerRenderer: function (params) {
var FLAG_CODES = {
'Ireland': 'ie',
'United States': 'us',
'Russia': 'ru',
'Australia': 'au',
'Canada': 'ca',
'Norway': 'no',
'China': 'cn',
'Zimbabwe': 'zw',
'Netherlands': 'nl',
'South Korea': 'kr',
'Croatia': 'hr',
'France': 'fr'
};
var flagCode = FLAG_CODES[params.node.key];
var html = '';
if (flagCode) {
html += '<img class="flag" border="0" width="20" height="15" src="https://flags.fmcdn.net/data/flags/mini/' + flagCode + '.png">'
}
html += '<span class="groupTitle"> COUNTRY_NAME</span>'.replace('COUNTRY_NAME', params.node.key);
html += '<span class="medal gold"> Gold: GOLD_COUNT</span>'.replace('GOLD_COUNT', params.data.gold);
html += '<span class="medal silver"> Silver: SILVER_COUNT</span>'.replace('SILVER_COUNT', params.data.silver);
html += '<span class="medal bronze"> Bronze: BRONZE_COUNT</span>'.replace('BRONZE_COUNT', params.data.bronze);
return html;
}
};
}
onGridReady(params) {
this.api = params.api;
this.columnApi = params.columnApi;
var that = this;
var httpRequest = new XMLHttpRequest();
httpRequest.open('GET', '/olympicWinners.json');
httpRequest.send();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
var httpResult = JSON.parse(httpRequest.responseText);
that.api.setRowData(httpResult);
}
};
}
render() {
var gridTemplate = (
<div style={{height: 400}} className="ag-fresh">
<AgGridReact
// gridOptions is optional - it's possible to provide
// all values as React props
gridOptions={this.gridOptions}
// listening for events
onGridReady={this.onGridReady.bind(this)}
// binding to array properties
columnDefs={this.state.columnDefs}
rowData={this.state.rowData}
groupUseEntireRow="true"
/>
</div>
);
return <div style={{width: '800px'}}>
<div>
{gridTemplate}
</div>
</div>;
}
}

View File

@@ -23,7 +23,13 @@ export default class ColDefFactory {
{headerName: "Country", field: "country", width: 150, enableRowGroup: true, enablePivot: true,
// an example of using a non-React cell renderer
cellRenderer: countryCellRenderer, pinned: true,
filterParams: {cellRenderer: countryCellRenderer, cellHeight: 20}},
filterParams: {cellRenderer: countryCellRenderer, cellHeight: 20}}
,
{headerName: "DOB", field: "dob", width: 90, enableRowGroup: true, enablePivot: true, filter:'date', cellRenderer: function(params) {
return pad(params.value.getDate(), 2) + '/' +
pad(params.value.getMonth() + 1, 2)+ '/' +
params.value.getFullYear();
}}
]
},
{
@@ -68,3 +74,10 @@ function countryCellRenderer(params) {
return null;
}
}
//Utility function used to pad the date formatting.
function pad(num, totalStringSize) {
let asString = num + "";
while (asString.length < totalStringSize) asString = "0" + asString;
return asString;
}

View File

@@ -0,0 +1,167 @@
import React from 'react';
// Date Component to be used in the date filter.
// This is a very simple example of how a React component can be plugged as a DateComponentFramework
// as you can see, the only requirement is that the React component implements the required methods
// getDate and setDate and that it calls back into props.onDateChanged every time that the date changes.
export default class MyReactDateComponent extends React.Component {
constructor(props) {
super(props);
//The state of this component is represented of:
// The current date it holds, null by default, null if the date typed by the user is not valid or fields are blank
// The current values that the user types in the input boxes, by default ''
//The textBoxes state is necessary since it can be set from ag-Grid. This can be seen in this example through
// the usage of the button DOB equals to 01/01/2000 in the example page.
this.state = {
date: null,
textBoxes: {
dd: '',
mm: '',
yyyy: ''
}
}
}
render() {
//Inlining styles to make simpler the component
let filterStyle = {
margin:'2px'
};
let ddStyle = {
width: '30px'
};
let mmStyle = {
width: '30px'
};
let yyyyStyle = {
width: '60px'
};
let resetStyle = {
padding: '2px',
backgroundColor: 'red',
borderRadius: '3px',
fontSize: '10px',
marginRight: '5px',
color: 'white'
};
return (
<div style={filterStyle}>
<span style={resetStyle} onClick={this.resetDate.bind(this)}>x</span>
<input onInput = {this.onDateChanged.bind(this)} ref="dd" placeholder="dd" style={ddStyle} value={this.state.textBoxes.dd} maxLength="2"/>/
<input onInput = {this.onDateChanged.bind(this)} ref="mm" placeholder="mm" style={mmStyle} value={this.state.textBoxes.mm} maxLength="2"/>/
<input onInput = {this.onDateChanged.bind(this)} ref="yyyy" placeholder="yyyy" style={yyyyStyle} value={this.state.textBoxes.yyyy} maxLength="4"/>
</div>
);
}
//*********************************************************************************
// METHODS REQUIRED BY AG-GRID
//*********************************************************************************
getDate (){
//ag-grid will call us here when in need to check what the current date value is hold by this
//component.
return this.state.date;
}
setDate (date){
//ag-grid will call us here when it needs this component to update the date that it holds.
this.setState({
date:date,
textBoxes:{
dd: date.getDate(),
mm: date.getMonth() + 1,
yyyy: date.getFullYear()
}
})
}
//*********************************************************************************
// LINKS THE INTERNAL STATE AND AG-GRID
//*********************************************************************************
updateAndNotifyAgGrid (date, textBoxes){
this.setState ({
date: date,
textBoxes:textBoxes
},
//Callback after the state is set. This is where we tell ag-grid that the date has changed so
//it will proceed with the filtering and we can then expect ag-Grid to call us back to getDate
this.props.onDateChanged
);
}
//*********************************************************************************
// LINKING THE UI, THE STATE AND AG-GRID
//*********************************************************************************
resetDate (){
let date = null;
let textBoxes = {
dd : '',
mm : '',
yyyy : '',
};
this.updateAndNotifyAgGrid(date, textBoxes)
}
onDateChanged () {
let date = this.parseDate(this.refs.dd.value, this.refs.mm.value, this.refs.yyyy.value);
let textBoxes = {
dd : this.refs.dd.value,
mm : this.refs.mm.value,
yyyy : this.refs.yyyy.value,
};
this.updateAndNotifyAgGrid(date, textBoxes)
}
//*********************************************************************************
// INTERNAL LOGIC
//*********************************************************************************
parseDate (dd, mm, yyyy){
//If any of the three input date fields are empty, stop and return null
if (dd.trim() === '' || mm.trim() === '' || yyyy.trim() === '') {
return null;
}
let day = Number(dd);
let month = Number(mm);
let year = Number(yyyy);
let date = new Date(year, month - 1, day);
//If the date is not valid
if (isNaN(date.getTime())){
return null;
}
//Given that new Date takes any garbage in, it is possible for the user to specify a new Date
//like this (-1, 35, 1) and it will return a valid javascript date. In this example, it will
//return Sat Dec 01 1 00:00:00 GMT+0000 (GMT) - Go figure...
//To ensure that we are not letting non sensical dates to go through we check that the resultant
//javascript date parts (month, year and day) match the given date fields provided as parameters.
//If the javascript date parts don't match the provided fields, we assume that the input is non
//sensical... ie: Day=-1 or month=14, if this is the case, we return null
//This also protects us from non sensical dates like dd=31, mm=2 of any year
if (date.getDate() != day || date.getMonth() + 1 != month || date.getFullYear() != year){
return null;
}
return date;
}
}
// the grid will always pass in one props called 'params',
// which is the grid passing you the params for the cellRenderer.
// this piece is optional. the grid will always pass the 'params'
// props, so little need for adding this validation meta-data.
MyReactDateComponent.propTypes = {
params: React.PropTypes.object
};

View File

@@ -56,6 +56,21 @@ RefData.COUNTRIES = [
{country: "Uruguay", continent: "South America", language: "Spanish"}
];
RefData.DOB = [
new Date(2000, 0, 1 ),
new Date(2001, 1, 2 ),
new Date(2002, 2, 3 ),
new Date(2003, 3, 4 ),
new Date(2004, 4, 5 ),
new Date(2005, 5, 6 ),
new Date(2006, 6, 7 ),
new Date(2007, 7, 8 ),
new Date(2008, 8, 9 ),
new Date(2009, 9, 10 ),
new Date(2010, 10, 11 ),
new Date(2011, 11, 12 )
];
RefData.ADDRESSES = [
'1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763',
'3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215',

View File

@@ -16,6 +16,7 @@ export default class RowDataFactory {
windows: Math.random() < 0.4,
css: Math.random() < 0.4
},
dob: RefData.DOB[i % RefData.DOB.length],
address: RefData.ADDRESSES[i % RefData.ADDRESSES.length],
years: Math.round(Math.random() * 100),
proficiency: Math.round(Math.random() * 100),

View File

@@ -71,6 +71,10 @@ export default class SkillsFilter extends React.Component {
this.setState(newModel, this.props.filterChangedCallback );
}
helloFromSkillsFilter() {
alert("Hello From The Skills Filter!");
}
render() {
var skillsTemplates = [];

View File

@@ -10,7 +10,7 @@ label {
.div-percent-bar {
display: inline-block;
height: 100%;
height: 20px;
position: relative;
}

View File

@@ -1,13 +1,12 @@
import ReactDOM from 'react-dom';
import React from 'react';
import {AgGridReact} from 'ag-grid-react';
import RefData from './RefData';
import RowDataFactory from './RowDataFactory';
import ColDefFactory from './ColDefFactory.jsx';
import './myApp.css';
import React from "react";
import {AgGridReact} from "ag-grid-react";
import RowDataFactory from "./RowDataFactory";
import ColDefFactory from "./ColDefFactory.jsx";
import MyReactDateComponent from "./MyReactDateComponent.jsx";
import "./myApp.css";
import "ag-grid-enterprise";
// take this line out if you do not want to use ag-Grid-Enterprise
import 'ag-grid-enterprise';
export default class MyApp extends React.Component {
@@ -39,8 +38,10 @@ export default class MyApp extends React.Component {
// you do, the providing the gridOptions as a standalone object is just
// what you want!
this.gridOptions = {
//We register the react date component that ag-grid will use to render
dateComponentFramework:MyReactDateComponent,
// this is how you listen for events using gridOptions
onModelUpdated: function() {
onModelUpdated: function () {
console.log('event onModelUpdated received');
},
// this is a simple property
@@ -94,6 +95,20 @@ export default class MyApp extends React.Component {
});
}
invokeSkillsFilterMethod() {
var skillsFilter = this.api.getFilterInstance('skills');
var componentInstance = skillsFilter.getFrameworkComponentInstance();
componentInstance.helloFromSkillsFilter();
}
dobFilter () {
let dateFilterComponent = this.gridOptions.api.getFilterInstance('dob');
dateFilterComponent.setFilterType('equals');
dateFilterComponent.setDateFrom('2000-01-01');
this.gridOptions.api.onFilterChanged();
}
render() {
var gridTemplate;
var bottomHeaderTemplate;
@@ -102,9 +117,14 @@ export default class MyApp extends React.Component {
topHeaderTemplate = (
<div>
<div style={{float: 'right'}}>
<input type="text" onChange={this.onQuickFilterText.bind(this)} placeholder="Type text to filter..."/>
<button id="btDestroyGrid" disabled={!this.state.showGrid} onClick={this.onShowGrid.bind(this, false)}>Destroy Grid</button>
<button id="btCreateGrid" disabled={this.state.showGrid} onClick={this.onShowGrid.bind(this, true)}>Create Grid</button>
<input type="text" onChange={this.onQuickFilterText.bind(this)}
placeholder="Type text to filter..."/>
<button id="btDestroyGrid" disabled={!this.state.showGrid}
onClick={this.onShowGrid.bind(this, false)}>Destroy Grid
</button>
<button id="btCreateGrid" disabled={this.state.showGrid} onClick={this.onShowGrid.bind(this, true)}>
Create Grid
</button>
</div>
<div style={{padding: '4px'}}>
<b>Employees Skills and Contact Details</b> <span id="rowCount"/>
@@ -130,11 +150,18 @@ export default class MyApp extends React.Component {
</div>
<div style={{clear: 'both'}}></div>
<div style={{padding: 4}} className={'toolbar'}>
<span>
<label>
<input type="checkbox" onChange={this.onToggleToolPanel.bind(this)}/>
Show Tool Panel
</label>
<button onClick={this.onRefreshData.bind(this)}>Refresh Data</button>
</span>
<span style={{marginLeft: 20}}>
Filter API:
<button onClick={this.invokeSkillsFilterMethod.bind(this, false)}>Invoke Skills Filter Method</button>
<button onClick={this.dobFilter.bind(this)}>DOB equals to 01/01/2000</button>
</span>
</div>
<div style={{clear: 'both'}}></div>
</div>
@@ -162,7 +189,8 @@ export default class MyApp extends React.Component {
columnDefs={this.state.columnDefs}
rowData={this.state.rowData}
// no binding, just providing harde coded strings for the properties
// no binding, just providing hard coded strings for the properties
suppressRowClickSelection="true"
rowSelection="multiple"
enableColResize="true"
enableSorting="true"

27
webpack.config.grouped.js Normal file
View File

@@ -0,0 +1,27 @@
module.exports = {
entry: "./src-grouped/index.js",
output: {
path: __dirname,
filename: "dist/bundle.js"
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style!css"
},
{
test: /\.js$|\.jsx$/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}
]
},
resolve: {
alias: {
"ag-grid-root" : __dirname + "/node_modules/ag-grid"
}
}
};