Compare commits

..

3 Commits
mgs ... ag49

Author SHA1 Message Date
Alberto
6d686f1c02 ag-49 Custom Group Header example completed 2017-02-03 11:16:17 +00:00
Alberto
6376a24e3a ag-49 Custom Header example completed 2017-02-03 10:14:20 +00:00
Sean Landsman
9c8cf08d2a AG-195 Create react example using grouped data 2017-01-26 11:40:46 +00:00
12 changed files with 9050 additions and 12 deletions

View File

@@ -16,6 +16,105 @@
margin-left: 4px; margin-left: 4px;
margin-right: 4px; margin-right: 4px;
} }
.customHeaderMenuButton{
margin-top: 5px;
margin-left: 4px;
float: left;
}
.customHeaderLabel{
margin-left: 5px;
margin-top: 3px;
float: left;
}
.customSortDownLabel{
float: left;
margin-left: 10px;
margin-top: 5px;
}
.customSortUpLabel{
float: left;
margin-left: 3px;
margin-top: 4px;
}
.customSortRemoveLabel{
float: left;
font-size: 11px;
margin-left: 3px;
margin-top: 6px;
}
.active {
color: cornflowerblue;
}
.hidden { display:none; }
.customHeaderLabel{
margin-left: 5px;
margin-top: 3px;
float: left;
}
.customExpandButton{
float:right;
margin-top: 5px;
margin-left: 3px;
}
.expanded {
animation-name: toExpanded;
animation-duration: 1s;
-ms-transform: rotate(180deg); /* IE 9 */
-webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
transform: rotate(180deg);
}
.collapsed {
color: cornflowerblue;
animation-name: toCollapsed;
animation-duration: 1s;
-ms-transform: rotate(0deg); /* IE 9 */
-webkit-transform: rotate(0deg); /* Chrome, Safari, Opera */
transform: rotate(0deg);
}
@keyframes toExpanded{
from {
color: cornflowerblue;
-ms-transform: rotate(0deg); /* IE 9 */
-webkit-transform: rotate(0deg); /* Chrome, Safari, Opera */
transform: rotate(0deg);
}
to {
color: black;
-ms-transform: rotate(180deg); /* IE 9 */
-webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
transform: rotate(180deg);
}
}
@keyframes toCollapsed{
from {
color: black;
-ms-transform: rotate(180deg); /* IE 9 */
-webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
transform: rotate(180deg);
}
to {
color: cornflowerblue;
-ms-transform: rotate(0deg); /* IE 9 */
-webkit-transform: rotate(0deg); /* Chrome, Safari, Opera */
transform: rotate(0deg);
}
}
</style> </style>
<body> <body>

8618
olympicWinners.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@
"main": "dist/ag-grid-react-example.js", "main": "dist/ag-grid-react-example.js",
"scripts": { "scripts": {
"standard": "webpack-dev-server --config webpack.config.standard.js --progress --colors --hot --inline", "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" "large": "webpack-dev-server --config webpack.config.large.js --progress --colors --hot --inline"
}, },
"repository": { "repository": {

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

@@ -4,6 +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';
export default class ColDefFactory { export default class ColDefFactory {
@@ -14,22 +15,28 @@ export default class ColDefFactory {
suppressMenu: true, pinned: true}, suppressMenu: true, pinned: true},
{ {
headerName: 'Employee', headerName: 'Employee',
headerGroupComponentFramework: MyReactHeaderGroupComponent,
children: [ children: [
{headerName: "Name", field: "name", enableRowGroup: true, enablePivot: true, {
headerName: "Name", field: "name", enableRowGroup: true, enablePivot: true,
width: 150, pinned: true, editable: 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: {cellRenderer: countryCellRenderer, cellHeight: 20}} filterParams: {
, cellRenderer: countryCellRenderer, cellHeight: 20
{headerName: "DOB", field: "dob", width: 90, enableRowGroup: true, enablePivot: true, filter:'date', cellRenderer: function(params) { }, columnGroupShow: 'open'
return pad(params.value.getDate(), 2) + '/' + }, {
pad(params.value.getMonth() + 1, 2)+ '/' + headerName: "DOB", field: "dob", width: 110, enableRowGroup: true, enablePivot: true, filter:'date',
params.value.getFullYear(); pinned: true, cellRenderer: function(params) {
}} return pad(params.value.getDate(), 2) + '/' +
pad(params.value.getMonth() + 1, 2)+ '/' +
params.value.getFullYear();
}, columnGroupShow: 'open'
}
] ]
}, },
{ {
@@ -41,7 +48,7 @@ export default class ColDefFactory {
// supply a React component // supply a React component
filterFramework: SkillsFilter filterFramework: SkillsFilter
}, },
{headerName: "Proficiency", field: "proficiency", width: 120, 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

View File

@@ -0,0 +1,76 @@
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.enableSorting){
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
};

View File

@@ -0,0 +1,41 @@
import React from 'react';
// Header component to be used as default for all the columns.
export default class MyReactHeaderGroupComponent extends React.Component {
constructor(props) {
super(props);
this.props.columnGroup.getOriginalColumnGroup().addEventListener('expandedChanged', this.onExpandChanged.bind(this));
this.state = {
expanded:null
}
this.onExpandChanged();
}
render() {
let arrowClassName = "customExpandButton " + (this.state.expanded ? " expanded": " collapsed");
return <div>
<div className="customHeaderLabel"> {this.props.displayName}</div>
<div onClick={this.expandOrCollapse.bind(this)} className={arrowClassName}><i className="fa fa-arrow-right" /></div>
</div>
}
expandOrCollapse (){
this.props.setExpanded(!this.state.expanded);
};
onExpandChanged (){
this.setState({
expanded: this.props.columnGroup.getOriginalColumnGroup().isExpanded()
})
}
}
// 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.
MyReactHeaderGroupComponent.propTypes = {
params: React.PropTypes.object
};

View File

@@ -3,6 +3,7 @@ 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 MyReactDateComponent from "./MyReactDateComponent.jsx";
import MyReactHeaderComponent from "./MyReactHeaderComponent.jsx";
import "./myApp.css"; import "./myApp.css";
import "ag-grid-enterprise"; import "ag-grid-enterprise";
@@ -44,6 +45,12 @@ export default class MyApp extends React.Component {
onModelUpdated: function () { onModelUpdated: function () {
console.log('event onModelUpdated received'); console.log('event onModelUpdated received');
}, },
defaultColDef : {
headerComponentFramework : MyReactHeaderComponent,
headerComponentParams : {
menuIcon: 'fa-bars'
}
},
// this is a simple property // this is a simple property
rowBuffer: 10 // no need to set this, the default is fine for almost all scenarios rowBuffer: 10 // no need to set this, the default is fine for almost all scenarios
}; };
@@ -203,7 +210,7 @@ export default class MyApp extends React.Component {
); );
} }
return <div style={{width: '800px'}}> return <div style={{width: '1024px'}}>
<div style={{padding: '4px'}}> <div style={{padding: '4px'}}>
{topHeaderTemplate} {topHeaderTemplate}
{bottomHeaderTemplate} {bottomHeaderTemplate}

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