Skip to content

Commit

Permalink
feat(transformData): add to every widget using the Template component
Browse files Browse the repository at this point in the history
- Refactored inside the Template component directly
- Changed the RefinementListComponent accordingly
- Added to widgets with their associated components:
  * Stats
  * Hits
  * Widgets

Closes #116
  • Loading branch information
Jerska committed Sep 24, 2015
1 parent 897a767 commit d080a03
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 12 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ search.addWidget(
// page: number
// processingTimeMS: number
// query: string
transformData: // function to modify the data passed to the template
})
);
```
Expand Down Expand Up @@ -312,7 +313,11 @@ search.addWidget(
hit // string (mustache format) or function(hit) return string
},
hitsPerPage: 20,
// cssClass
// cssClass,
// transformData: {
// empty, // function to modify the data passed to the empty template
// hit // function to modify the data passed to the hit template
// }
})
);
```
Expand Down Expand Up @@ -356,6 +361,7 @@ search.addWidget(
* @param {String} options.facetName Name of the attribute for faceting (eg. "free_shipping")
* @param {String} options.label Human-readable name of the filter (eg. "Free Shipping")
* @param {String|Function} [options.template] Item template, provided with `label` and `isRefined`
* @param {Function} [options.transformData] Function to change the object passed to the item template
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
Expand Down Expand Up @@ -386,6 +392,7 @@ search.addWidget(
<input type="checkbox" value="{{name}}" {{#isRefined}}checked{{/isRefined}} />{{name}} <span>{{count}}</span>
</label>`] Item template, provided with `name`, `count`, `isRefined`
* @param {String|Function} [options.templates.footer] Footer template
* @param {Function} [options.transformData] Function to change the object passed to the item template
* @param {String|Function} [options.singleRefine=true] Are multiple refinements allowed or only one at the same time. You can use this
* to build radio based refinement lists for example
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
Expand Down Expand Up @@ -431,6 +438,7 @@ search.addWidget(
* @param {String|Function} [options.templates.header=''] Header template
* @param {String|Function} [options.templates.item='<a href="{{href}}">{{name}}</a> {{count}}'] Item template, provided with `name`, `count`, `isRefined`
* @param {String|Function} [options.templates.footer=''] Footer template
* @param {Function} [options.transformData] Function to change the object passed to the item template
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
Expand Down
28 changes: 25 additions & 3 deletions components/Hits.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,36 @@ var Template = require('./Template');

class Hits extends React.Component {
renderWithResults() {
var template = this.props.hitTemplate;
var transformData = this.props.hitTransformData;

var renderedHits = map(this.props.hits, function(hit) {
return <Template data={hit} key={hit.objectID} template={this.props.hitTemplate} />;
return (
<Template
data={hit}
transformData={transformData}
key={hit.objectID}
template={template}
/>
);
}, this);

return <div>{renderedHits}</div>;
}

renderNoResults() {
var data = this.props.results;
var template = this.props.noResultsTemplate;
var transformData = this.props.noResultsTransformData;

return (
<div><Template data={this.props.results} template={this.props.noResultsTemplate} /></div>
<div>
<Template
data={data}
transformData={transformData}
template={template}
/>
</div>
);
}

Expand All @@ -32,10 +52,12 @@ Hits.propTypes = {
React.PropTypes.string,
React.PropTypes.func
]).isRequired,
hitTransformData: React.PropTypes.func,
noResultsTemplate: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.func
]).isRequired
]).isRequired,
noResultsTransformData: React.PropTypes.func
};

Hits.defaultProps = {
Expand Down
7 changes: 6 additions & 1 deletion components/RefinementList.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class RefinementList extends React.Component {
render() {
var facetValues = this.props.facetValues;
var templates = this.props.templates;
var transformData = this.props.transformData;
var rootClass = cx(this.props.cssClasses.root);
var listClass = cx(this.props.cssClasses.list);
var itemClass = cx(this.props.cssClasses.item);
Expand All @@ -56,7 +57,11 @@ class RefinementList extends React.Component {
{facetValues.map(facetValue => {
return (
<div className={itemClass} key={facetValue.name} onClick={this.handleClick.bind(this, facetValue.name)}>
<Template data={(this.props.transformData) ? this.props.transformData(facetValue) : facetValue} template={templates.item} />
<Template
data={facetValue}
transformData={transformData}
template={templates.item}
/>
</div>
);
})}
Expand Down
3 changes: 3 additions & 0 deletions components/Stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Stats extends React.Component {
render() {
var template = this.props.template;
var templateHelpers = this.props.templateHelpers;
var transformData = this.props.transformData;
var data = {
hasManyResults: this.props.nbHits > 1,
hasNoResults: this.props.nbHits === 0,
Expand All @@ -22,6 +23,7 @@ class Stats extends React.Component {
return (
<Template
data={data}
transformData={transformData}
template={template}
templateHelpers={templateHelpers}
/>
Expand All @@ -39,6 +41,7 @@ Stats.propTypes = {
React.PropTypes.func,
React.PropTypes.string
]).isRequired,
transformData: React.PropTypes.func,
templateHelpers: React.PropTypes.object,
query: React.PropTypes.string
};
Expand Down
3 changes: 2 additions & 1 deletion components/Template.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Template {
var content = renderTemplate({
template: this.props.template,
templateHelpers: this.props.templateHelpers,
data: this.props.data
data: this.props.transformData ? this.props.transformData(this.props.data) : this.props.data
});

return <div dangerouslySetInnerHTML={{__html: content}} />;
Expand All @@ -20,6 +20,7 @@ Template.propTypes = {
React.PropTypes.func
]).isRequired,
templateHelpers: React.PropTypes.object,
transformData: React.PropTypes.func,
data: React.PropTypes.object
};

Expand Down
8 changes: 7 additions & 1 deletion components/Toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var debounce = require('lodash/function/debounce');
class Toggle extends React.Component {
render() {
var template = this.props.template;
var transformData = this.props.transformData;
// When a checkbox is wrapped inside a label, click events fire twice, so we
// debounce it to only keep the first one
var toggleFilter = debounce(this.props.toggleFilter, 0, {
Expand All @@ -20,7 +21,11 @@ class Toggle extends React.Component {

return (
<span onClick={toggleFilter}>
<Template data={data} template={template} />
<Template
data={data}
transformData={transformData}
template={template}
/>
</span>
);
}
Expand All @@ -31,6 +36,7 @@ Toggle.propTypes = {
React.PropTypes.string,
React.PropTypes.func
]).isRequired,
transformData: React.PropTypes.func,
toggleFilter: React.PropTypes.func.isRequired,
label: React.PropTypes.string,
isRefined: React.PropTypes.bool
Expand Down
7 changes: 5 additions & 2 deletions widgets/hits.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ var utils = require('../lib/utils.js');
function hits({
container = null,
templates = {},
hitsPerPage = 20,
hideIfEmpty = false
transformData = {},
hideIfEmpty = false,
hitsPerPage = 20
}) {
var Hits = require('../components/Hits');

Expand All @@ -21,9 +22,11 @@ function hits({
results={results}
helper={helper}
noResultsTemplate={templates.empty}
noResultsTransformData={transformData.empty}
hideIfEmpty={hideIfEmpty}
hasResults={results.hits.length > 0}
hitTemplate={templates.hit}
hitTransformData={transformData.hit}
/>,
containerNode
);
Expand Down
2 changes: 1 addition & 1 deletion widgets/refinement-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var defaults = require('lodash/object/defaults');
<input type="checkbox" value="{{name}}" {{#isRefined}}checked{{/isRefined}} />{{name}} <span>{{count}}</span>
</label>`] Item template, provided with `name`, `count`, `isRefined`
* @param {String|Function} [options.templates.footer] Footer template
* @param {Function} [options.transformData] Method to change the object passed to the item template
* @param {Function} [options.transformData] Function to change the object passed to the item template
* @param {String|Function} [options.singleRefine=true] Are multiple refinements allowed or only one at the same time. You can use this
* to build radio based refinement lists for example
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
Expand Down
4 changes: 3 additions & 1 deletion widgets/stats/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ var defaultTemplate = require('./template.html');
function stats({
container = null,
template = defaultTemplate,
transformData = null,
hideIfEmpty = true
}) {
var Stats = require('../../components/Stats');
var containerNode = utils.getContainerNode(container);

if (container === null) {
throw new Error('Usage: stats({container})');
throw new Error('Usage: stats({container[, template, transformData]})');
}

return {
Expand All @@ -29,6 +30,7 @@ function stats({
query={results.query}
templateHelpers={templateHelpers}
template={template}
transformData={transformData}
/>,
containerNode
);
Expand Down
5 changes: 4 additions & 1 deletion widgets/toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var defaultTemplate = '<label>{{label}}<input type="checkbox" {{#isRefined}}chec
* @param {String} options.facetName Name of the attribute for faceting (eg. "free_shipping")
* @param {String} options.label Human-readable name of the filter (eg. "Free Shipping")
* @param {String|Function} [options.template] Item template, provided with `label` and `isRefined`
* @param {Function} [options.transformData] Function to change the object passed to the item template
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
* @return {Object}
*/
Expand All @@ -19,12 +20,13 @@ function toggle({
facetName = null,
label = null,
template = defaultTemplate,
transformData = null,
hideIfEmpty = true
}) {
var Toggle = require('../components/Toggle');

var containerNode = utils.getContainerNode(container);
var usage = 'Usage: toggle({container, facetName, label})';
var usage = 'Usage: toggle({container, facetName, label[, template, transformData]})';

if (container === null || facetName === null || label === null) {
throw new Error(usage);
Expand All @@ -47,6 +49,7 @@ function toggle({
isRefined={isRefined}
label={label}
template={template}
transformData={transformData}
hideIfEmpty={hideIfEmpty}
hasResults={results.hits.length > 0}
toggleFilter={toggleFilter}
Expand Down

0 comments on commit d080a03

Please sign in to comment.