Skip to content

Commit

Permalink
Merge pull request #150 from KleeGroup/list-example
Browse files Browse the repository at this point in the history
List example
  • Loading branch information
pierr committed Jul 30, 2015
2 parents 26f4b81 + 6e83de8 commit 3852fdb
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 53 deletions.
9 changes: 8 additions & 1 deletion common/form/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ var formMixin = {
* @type {Boolean}
*/
hasDelete: false,
/**
* Does the form call the load action on componentdid mount.
* @type {Boolean}
*/
hasLoad: true,
/**
* Defines
* @type {Boolean}
Expand All @@ -58,7 +63,9 @@ var formMixin = {
},
/** @inheritdoc */
callMountedActions: function formCallMountedActions() {
this._loadData();
if(this.props.hasLoad){
this._loadData();
}
this._loadReference();
},
/** @inheritdoc */
Expand Down
99 changes: 52 additions & 47 deletions common/form/mixin/action-behaviour.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,76 @@
var assign = require('object-assign');
var isFunction = require('lodash/lang/isFunction');
var omit = require('lodash/object/omit');
var actionMixin = {
let assign = require('object-assign');
let isFunction = require('lodash/lang/isFunction');
let omit = require('lodash/object/omit');
let {FocusException} = require('focus').exception;
let actionMixin = {

/**
* Get the entity identifier for the form loading.
* @returns {object} - The identifier of the entity.
*/
_getId: function formGetId() {
if(this.getId){
return this.getId();
}
return this.state.id;
},
_getId() {
if(this.getId){
return this.getId();
}
return this.state.id;
},
/**
* Get a clean state to send data to the server.
* @returns {object} - The state json cleanded
*/
_getCleanState: function(){
return omit(this.state, ['reference', 'isLoading', 'isEdit']);
},
_getCleanState(){
return omit(this.state, ['reference', 'isLoading', 'isEdit']);
},
/**
* Compute the entity read from the html givent the keys and the definition Path, this operation is reversed from the _computeEntityFromStore operation.
* @param {object} htmlData - Data read from the html form.
* @returns {object} - The computed entity from html.
*/
_computeEntityFromHtml: function(htmlData){
const DEF = `${this.definitionPath}.`;
const EMPTY = '';
let computedEntity = {};
for(let prop in htmlData){
computedEntity[prop.replace(DEF, EMPTY)] = htmlData[prop];
}
return computedEntity;
},
_computeEntityFromHtml(htmlData){
const DEF = `${this.definitionPath}.`;
const EMPTY = '';
let computedEntity = {};
for(let prop in htmlData){
computedEntity[prop.replace(DEF, EMPTY)] = htmlData[prop];
}
return computedEntity;
},
/**
* Get the constructed entity from the state.
* @returns {object} - the entity informations.
*/
_getEntity: function formGetEntity(){
if(this.getEntity){
return this.getEntity();
}
//Build the entity value from the ref getVaue.
var htmlData = {};
for(var r in this.refs){
//If the reference has a getValue function if is read.
if(this.refs[r] && isFunction(this.refs[r].getValue)){
htmlData[r] = this.refs[r].getValue();
}
}
//Maybe a merge cold be done if we need a deeper property merge.
return assign({}, this._getCleanState(), this._computeEntityFromHtml(htmlData));
},
_getEntity(){
if(this.getEntity){
return this.getEntity();
}
//Build the entity value from the ref getVaue.
let htmlData = {};
for(let r in this.refs){
//If the reference has a getValue function if is read.
if(this.refs[r] && isFunction(this.refs[r].getValue)){
htmlData[r] = this.refs[r].getValue();
}
}
//Maybe a merge cold be done if we need a deeper property merge.
return assign({}, this._getCleanState(), this._computeEntityFromHtml(htmlData));
},
/**
* Load data action call.
*/
_loadData: function formLoadData() {
this.action.load(this._getId());
},
clearError(){
for(var r in this.refs){
//If the reference has a getValue function if is read.
if(this.refs[r] && isFunction(this.refs[r].getValue)){
this.refs[r].setError(undefined);
}
_loadData(){
if(!this.action || !isFunction(this.action.load)){
throw new FocusException('It seems your form component does not have a load action, and your props is set to hasLoad={true}.', this);
}
this.action.load(this._getId());
},
clearError(){
for(let r in this.refs){
//If the reference has a getValue function if is read.
if(this.refs[r] && isFunction(this.refs[r].getValue)){
this.refs[r].setError(undefined);
}
}
}
}
};


Expand Down
2 changes: 1 addition & 1 deletion common/mixin/store-change-behaviour.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var changeBehaviourMixin = {
Focus.message.addInformationMessage('detail.saving');
break;*/
case 'saved':
if(this.props.hasForm){
if(this.props.hasForm){ //See https://github.com/KleeGroup/focus-components/issues/148
Focus.message.addSuccessMessage('detail.saved');
//Change the page mode as edit
this.setState({isEdit: false});
Expand Down
108 changes: 104 additions & 4 deletions page/list/example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@

</head>
<body>
<h1>List examples</h1>
<h2>Simple list</h2>
<div id="list-container" style=" width:70%;margin: auto;"></div>

<script type="text/jsx">
/*SIMPLE LIST EXAMPLE (NO CRITERIA)*/
var countId = 0;
var service = function (criteria) {
console.log('criteria', criteria);
Expand All @@ -55,7 +57,7 @@
return {dataList: d, totalCount: fakeData.length}
});
};

//Creates a line for the component.
var Line = React.createClass({
mixins: [FocusComponents.list.table.line.mixin],
definitionPath: "contact",
Expand All @@ -70,9 +72,95 @@
);
}
});

//Creates a store for the list.
var listStore = new Focus.store.ListStore({identifier: 'LIST_TEST'});
//Creates the props for the page.
var listPageProps = {
onLineClick: function onLineClick(line) {
alert('click sur la ligne ' + line.id);
},
lineComponent: Line,
store: listStore,
service: service
};
var ListPage = FocusComponents.page.list.component;

//React.render(<ListPage {...listPageProps} />, document.querySelector("#list-container"));
</script>

<h2> List with criteria</h2>
<span>Type a number to filte the list</span>
<div id='list-criteria-container' style=" width:70%;margin: auto;"></div>
<script type="text/jsx">
//Fake data
var fakeData = [];
for(var i = 0; i < 150; i++){
fakeData.push({
id: i,
firstName: 'firstName ' + i,
lastName: 'lastName ' + i,
birthDate: Date.now(),
age : i
})
}

/*SIMPLE LIST EXAMPLE (NO CRITERIA)*/
var countId = 0;
var service = function (searchOptions) {
var criteria = searchOptions.data.criteria || {};
var filteredData = fakeData.filter(function(element){
return (element.age || 0) < (criteria.age || 150);
})
var begin = searchOptions.urlData.skip;
var end = begin + searchOptions.urlData.top;
return Promise.resolve(filteredData.slice(begin, end)).then(function(d){
return {dataList: d, totalCount: filteredData.length}
});
};
var action = function(criteria){

}
var Button = FocusComponents.common.button.action.component;
var listStore = new Focus.store.ListStore({identifier: 'LIST_CRITERIA_TEST'});

//Criteria component
var Criteria = React.createClass({
definitionPath: "contact",
mixins: [FocusComponents.common.form.mixin],

handleSearch: function(event){
var criteria = this._getEntity();
Focus.dispatcher.handleViewAction({
data: {criteria: criteria},
type: 'update',
identifier: listStore.identifier
});
},
renderContent: function(){
return(
<div className='SearchComponent'>
{this.fieldFor('age')}
<Button handleOnClick={this.handleSearch}/>
</div>
);
}
})
//List component
//Creates a line for the component.
var Line = React.createClass({
mixins: [FocusComponents.list.table.line.mixin],
definitionPath: "contact",
renderLineContent: function(data){
return (
<tr onClick={this.props.onLineClick}>
<td>{this.textFor("firstName", {})}</td>
<td>{this.textFor("lastName", {})}</td>
<td>{this.textFor("birthDate", {})}</td>
</tr>
);
}
});
//Creates the props for the page.
var listPageProps = {
onLineClick: function onLineClick(line) {
alert('click sur la ligne ' + line.id);
Expand All @@ -83,9 +171,21 @@
};
var ListPage = FocusComponents.page.list.component;

React.render(<ListPage {...listPageProps} />, document.querySelector("#list-container"));

var CriteriaPage = React.createClass({
render: function renderCriteriaPage(){
return (
<div className='CriteriaPage'>
<Criteria isEdit={true} hasForm={false} hasLoad={false}/>
<ListPage {...listPageProps} />
</div>
);
}
});
React.render( <CriteriaPage id />, document.querySelector("#list-criteria-container"));
</script>


</body>

</html>
5 changes: 5 additions & 0 deletions page/list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,13 @@ let listPageMixin = {
*/
_registerStoreNode(){
STORE_NODE.forEach((node)=>{
//Maybe this is a bit too much, a global change event could be more efficient as almost all store props change.
this.props.store[_listenerProp(node)](this._handleStoreChanged)
});
//When the criteria is changed, the search is triggered.
this.props.store.addCriteriaChangeListener(()=>{
this._action.load();
})
},
/**
* build the list props.
Expand Down

0 comments on commit 3852fdb

Please sign in to comment.