Skip to content
This repository was archived by the owner on Aug 19, 2024. It is now read-only.

Commit 351d93b

Browse files
committed
AG-530 Implement React declarative offering
1 parent 43af123 commit 351d93b

19 files changed

Lines changed: 1287 additions & 162 deletions

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"css-loader": "0.23.x",
4848
"mkdirp": "0.5.1",
4949
"ncp": "2.0.0",
50-
"prop-types": "15.5.x",
50+
"prop-types": "15.6.0",
5151
"rimraf": "2.5.x",
5252
"style-loader": "0.13.x",
5353
"webpack": "1.12.x",
@@ -65,9 +65,9 @@
6565
"d3": "4.9.1",
6666
"file-loader": "0.11.1",
6767
"lodash": "4.17.4",
68-
"react": "15.6.x",
69-
"react-dom": "15.6.x",
70-
"react-dom-factories": "1.0.0",
68+
"react": "16.0.0",
69+
"react-dom": "16.0.0",
70+
"react-dom-factories": "1.0.2",
7171
"react-redux": "5.0.x",
7272
"react-router-dom": "4.2.x",
7373
"redux": "3.6.x",

src/App.jsx

Lines changed: 3 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import NavItem from "./NavItem";
55

66
import DynamicComponentsExample from "./dynamicComponentExample/DynamicComponentsExample";
77
import RichGridExample from "./richGridExample/RichGridExample";
8+
import RichGridDeclarativeExample from "./richGridDeclarativeExample/RichGridDeclarativeExample";
89
import RichComponentsExample from "./richComponentExample/RichComponentsExample";
910
import EditorComponentsExample from "./editorComponentExample/EditorComponentsExample";
1011
import PinnedRowComponentExample from "./pinnedRowExample/PinnedRowComponentExample";
@@ -20,6 +21,7 @@ const SideBar = () => (
2021
<div style={{float: "left", width: 335, marginRight: 25}}>
2122
<ul className="nav nav-pills nav-stacked">
2223
<NavItem to='/rich-grid'>Rich Grid Example</NavItem>
24+
<NavItem to='/rich-grid-declarative'>Rich Grid with Declarative Markup</NavItem>
2325
<NavItem to='/dynamic'>Dynamic React Component Example</NavItem>
2426
<NavItem to='/rich-dynamic'>Dynamic React Components - Richer Example</NavItem>
2527
<NavItem to='/editor'>Cell Editor Component Example</NavItem>
@@ -44,6 +46,7 @@ class App extends Component {
4446
<Switch>
4547
<Redirect from="/" exact to="/rich-grid"/>
4648
<Route exact path='/rich-grid' component={RichGridExample}/>
49+
<Route exact path='/rich-grid-declarative' component={RichGridDeclarativeExample}/>
4750
<Route exact path='/dynamic' component={DynamicComponentsExample}/>
4851
<Route exact path='/rich-dynamic' component={RichComponentsExample}/>
4952
<Route exact path='/editor' component={EditorComponentsExample}/>
@@ -63,97 +66,3 @@ class App extends Component {
6366
}
6467

6568
export default App
66-
67-
/*
68-
class App extends Component {
69-
constructor(props) {
70-
super(props);
71-
72-
let searchParams = new URLSearchParams(window.location.search);
73-
let fromDocs = searchParams.has("fromDocs");
74-
let example = searchParams.has("example") ? searchParams.get("example") : 'rich-grid';
75-
76-
this.state = {
77-
example,
78-
fromDocs
79-
};
80-
81-
this.setExample = this.setExample.bind(this);
82-
}
83-
84-
setExample(example) {
85-
this.setState({
86-
example
87-
})
88-
}
89-
90-
render() {
91-
let header = null;
92-
if (!this.state.fromDocs) {
93-
header = (
94-
<ul className="nav nav-pills">
95-
<li role="presentation" className={this.state.example === 'rich-grid' ? 'active' : null} onClick={() => this.setExample("rich-grid")}><a href="#">Rich Grid Example</a></li>
96-
<li role="presentation" className={this.state.example === 'dynamic' ? 'active' : null} onClick={() => this.setExample("dynamic")}><a href="#">Dynamic React Component Example</a></li>
97-
<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>
98-
<li role="presentation" className={this.state.example === 'editor' ? 'active' : null} onClick={() => this.setExample("editor")}><a href="#">Cell Editor Component Example</a></li>
99-
<li role="presentation" className={this.state.example === 'pinned-row' ? 'active' : null} onClick={() => this.setExample("pinned-row")}><a href="#">Pinned Row Renderer Example</a></li>
100-
<li role="presentation" className={this.state.example === 'full-width' ? 'active' : null} onClick={() => this.setExample("full-width")}><a href="#">Full Width Renderer Example</a></li>
101-
<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>
102-
<li role="presentation" className={this.state.example === 'filter' ? 'active' : null} onClick={() => this.setExample("filter")}><a href="#">Filters Component Example</a></li>
103-
<li role="presentation" className={this.state.example === 'floating-filter' ? 'active' : null} onClick={() => this.setExample("floating-filter")}><a href="#">Floating Filters</a></li>
104-
<li role="presentation" className={this.state.example === 'master-detail' ? 'active' : null} onClick={() => this.setExample("master-detail")}><a href="#">Master Detail Example</a></li>
105-
<li role="presentation" className={this.state.example === 'simple-redux' ? 'active' : null} onClick={() => this.setExample("simple-redux")}><a href="#">Simple Redux Example</a></li>
106-
<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>
107-
</ul>)
108-
}
109-
110-
let example = null;
111-
switch (this.state.example) {
112-
case 'dynamic':
113-
example = <DynamicComponentsExample/>;
114-
break;
115-
case 'rich-dynamic':
116-
example = <RichComponentsExample/>;
117-
break;
118-
case 'editor':
119-
example = <EditorComponentsExample/>;
120-
break;
121-
case 'pinned-row':
122-
example = <PinnedRowComponentExample/>;
123-
break;
124-
case 'full-width':
125-
example = <FullWidthComponentExample/>;
126-
break;
127-
case 'group-row':
128-
example = <GroupedRowInnerRendererComponentExample/>;
129-
break;
130-
case 'filter':
131-
example = <FilterComponentExample/>;
132-
break;
133-
case 'master-detail':
134-
example = <MasterDetailExample/>;
135-
break;
136-
case 'simple-redux':
137-
example = <SimpleReduxExample/>;
138-
break;
139-
case 'floating-filter':
140-
example = <FloatingFilterGridExample/>;
141-
break;
142-
case 'simple-redux-dynamic':
143-
example = <SimpleReduxDynamicExample/>;
144-
break;
145-
default:
146-
example = <RichGridExample/>;
147-
}
148-
149-
return (
150-
<div>
151-
{header}
152-
{example}
153-
</div>
154-
)
155-
}
156-
}
157-
158-
export default App
159-
*/

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import React from "react";
44
import {render} from "react-dom";
55
import {BrowserRouter} from "react-router-dom";
66

7-
import "ag-grid-root/dist/styles/ag-grid.css";
8-
import "ag-grid-root/dist/styles/theme-fresh.css";
7+
import "ag-grid/dist/styles/ag-grid.css";
8+
import "ag-grid/dist/styles/theme-fresh.css";
99
import "../node_modules/bootstrap/dist/css/bootstrap.css";
1010

1111
import App from "./App";
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import React from "react";
2+
import * as PropTypes from "prop-types";
3+
4+
// Date Component to be used in the date filter.
5+
// This is a very simple example of how a React component can be plugged as a DateComponentFramework
6+
// as you can see, the only requirement is that the React component implements the required methods
7+
// getDate and setDate and that it calls back into props.onDateChanged every time that the date changes.
8+
export default class DateComponent extends React.Component {
9+
10+
constructor(props) {
11+
super(props);
12+
//The state of this component is represented of:
13+
// The current date it holds, null by default, null if the date typed by the user is not valid or fields are blank
14+
// The current values that the user types in the input boxes, by default ''
15+
16+
//The textBoxes state is necessary since it can be set from ag-Grid. This can be seen in this example through
17+
// the usage of the button DOB equals to 01/01/2000 in the example page.
18+
this.state = {
19+
date: null,
20+
textBoxes: {
21+
dd: '',
22+
mm: '',
23+
yyyy: ''
24+
}
25+
}
26+
}
27+
28+
render() {
29+
//Inlining styles to make simpler the component
30+
let filterStyle = {
31+
margin: '2px'
32+
};
33+
let ddStyle = {
34+
width: '30px'
35+
};
36+
let mmStyle = {
37+
width: '30px'
38+
};
39+
let yyyyStyle = {
40+
width: '40px'
41+
};
42+
let resetStyle = {
43+
padding: '2px',
44+
backgroundColor: 'red',
45+
borderRadius: '3px',
46+
fontSize: '10px',
47+
marginRight: '5px',
48+
color: 'white'
49+
};
50+
51+
return (
52+
<div style={filterStyle}>
53+
<span style={resetStyle} onClick={this.resetDate.bind(this)}>x</span>
54+
<input onInput={this.onDateChanged.bind(this)} ref="dd" placeholder="dd" style={ddStyle}
55+
value={this.state.textBoxes.dd} maxLength="2"/>/
56+
<input onInput={this.onDateChanged.bind(this)} ref="mm" placeholder="mm" style={mmStyle}
57+
value={this.state.textBoxes.mm} maxLength="2"/>/
58+
<input onInput={this.onDateChanged.bind(this)} ref="yyyy" placeholder="yyyy" style={yyyyStyle}
59+
value={this.state.textBoxes.yyyy} maxLength="4"/>
60+
</div>
61+
);
62+
}
63+
64+
//*********************************************************************************
65+
// METHODS REQUIRED BY AG-GRID
66+
//*********************************************************************************
67+
68+
getDate() {
69+
//ag-grid will call us here when in need to check what the current date value is hold by this
70+
//component.
71+
return this.state.date;
72+
}
73+
74+
setDate(date) {
75+
//ag-grid will call us here when it needs this component to update the date that it holds.
76+
this.setState({
77+
date,
78+
textBoxes: {
79+
dd: date ? date.getDate() : '',
80+
mm: date ? date.getMonth() + 1 : '',
81+
yyyy: date ? date.getFullYear() : ''
82+
}
83+
})
84+
}
85+
86+
//*********************************************************************************
87+
// LINKS THE INTERNAL STATE AND AG-GRID
88+
//*********************************************************************************
89+
90+
updateAndNotifyAgGrid(date, textBoxes) {
91+
this.setState({
92+
date: date,
93+
textBoxes: textBoxes
94+
},
95+
//Callback after the state is set. This is where we tell ag-grid that the date has changed so
96+
//it will proceed with the filtering and we can then expect ag-Grid to call us back to getDate
97+
this.props.onDateChanged
98+
);
99+
}
100+
101+
102+
//*********************************************************************************
103+
// LINKING THE UI, THE STATE AND AG-GRID
104+
//*********************************************************************************
105+
106+
resetDate() {
107+
let date = null;
108+
let textBoxes = {
109+
dd: '',
110+
mm: '',
111+
yyyy: '',
112+
};
113+
114+
this.updateAndNotifyAgGrid(date, textBoxes)
115+
}
116+
117+
onDateChanged() {
118+
let date = this.parseDate(this.refs.dd.value, this.refs.mm.value, this.refs.yyyy.value);
119+
let textBoxes = {
120+
dd: this.refs.dd.value,
121+
mm: this.refs.mm.value,
122+
yyyy: this.refs.yyyy.value,
123+
};
124+
125+
this.updateAndNotifyAgGrid(date, textBoxes)
126+
}
127+
128+
//*********************************************************************************
129+
// INTERNAL LOGIC
130+
//*********************************************************************************
131+
132+
parseDate(dd, mm, yyyy) {
133+
//If any of the three input date fields are empty, stop and return null
134+
if (dd.trim() === '' || mm.trim() === '' || yyyy.trim() === '') {
135+
return null;
136+
}
137+
138+
let day = Number(dd);
139+
let month = Number(mm);
140+
let year = Number(yyyy);
141+
142+
let date = new Date(year, month - 1, day);
143+
144+
//If the date is not valid
145+
if (isNaN(date.getTime())) {
146+
return null;
147+
}
148+
149+
//Given that new Date takes any garbage in, it is possible for the user to specify a new Date
150+
//like this (-1, 35, 1) and it will return a valid javascript date. In this example, it will
151+
//return Sat Dec 01 1 00:00:00 GMT+0000 (GMT) - Go figure...
152+
//To ensure that we are not letting non sensical dates to go through we check that the resultant
153+
//javascript date parts (month, year and day) match the given date fields provided as parameters.
154+
//If the javascript date parts don't match the provided fields, we assume that the input is non
155+
//sensical... ie: Day=-1 or month=14, if this is the case, we return null
156+
//This also protects us from non sensical dates like dd=31, mm=2 of any year
157+
if (date.getDate() != day || date.getMonth() + 1 != month || date.getFullYear() != year) {
158+
return null;
159+
}
160+
161+
return date;
162+
}
163+
}
164+
165+
// the grid will always pass in one props called 'params',
166+
// which is the grid passing you the params for the cellRenderer.
167+
// this piece is optional. the grid will always pass the 'params'
168+
// props, so little need for adding this validation meta-data.
169+
DateComponent.propTypes = {
170+
params: PropTypes.object
171+
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from 'react';
2+
import * as PropTypes from 'prop-types';
3+
4+
// Header component to be used as default for all the columns.
5+
export default class HeaderGroupComponent extends React.Component {
6+
7+
constructor(props) {
8+
super(props);
9+
this.props.columnGroup.getOriginalColumnGroup().addEventListener('expandedChanged', this.onExpandChanged.bind(this));
10+
this.state = {
11+
expanded: null
12+
};
13+
}
14+
15+
componentDidMount() {
16+
this.onExpandChanged();
17+
}
18+
19+
render() {
20+
let arrowClassName = "customExpandButton " + (this.state.expanded ? " expanded" : " collapsed");
21+
22+
return <div>
23+
<div className="customHeaderLabel"> {this.props.displayName}</div>
24+
<div onClick={this.expandOrCollapse.bind(this)} className={arrowClassName}><i
25+
className="fa fa-arrow-right"/></div>
26+
</div>
27+
}
28+
29+
expandOrCollapse() {
30+
this.props.setExpanded(!this.state.expanded);
31+
};
32+
33+
onExpandChanged() {
34+
this.setState({
35+
expanded: this.props.columnGroup.getOriginalColumnGroup().isExpanded()
36+
})
37+
}
38+
}
39+
40+
// the grid will always pass in one props called 'params',
41+
// which is the grid passing you the params for the cellRenderer.
42+
// this piece is optional. the grid will always pass the 'params'
43+
// props, so little need for adding this validation meta-data.
44+
HeaderGroupComponent.propTypes = {
45+
params: PropTypes.object
46+
};

0 commit comments

Comments
 (0)