Skip to content

Commit 187b4bd

Browse files
author
vvo
committed
feat(widgets): auto hide some widgets
We now auto hide: - refinementList - menu - rangeSlider - toggle - pagination + option hideWhenNoResults available for all widgets + refactor the way we handle hiding: now somehow a decorator, see: - https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775 - https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775#gistcomment-1574787 For more details, or ask me.
1 parent 8435bc5 commit 187b4bd

18 files changed

+121
-60
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ search.addWidget(
264264
* @param {String|DOMElement} options.container Valid CSS Selector as a string or DOMElement
265265
* @param {Array} options.indices Array of objects defining the different indices to choose from. Each object must contain a `name` and `label` key.
266266
* @param {String} [options.cssClass] Class name(s) to be added to the generated select element
267+
* @param {boolean} [hideIfEmpty=false] Hide the container when no results match
267268
* @return {Object}
268269
*/
269270
```
@@ -355,6 +356,7 @@ search.addWidget(
355356
* @param {String} options.facetName Name of the attribute for faceting (eg. "free_shipping")
356357
* @param {String} options.label Human-readable name of the filter (eg. "Free Shipping")
357358
* @param {String|Function} [options.template] Item template, provided with `label` and `isRefined`
359+
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
358360
* @return {Object}
359361
*/
360362
```
@@ -386,7 +388,7 @@ search.addWidget(
386388
* @param {String|Function} [options.templates.footer] Footer template
387389
* @param {String|Function} [options.singleRefine=true] Are multiple refinements allowed or only one at the same time. You can use this
388390
* to build radio based refinement lists for example
389-
* @param {boolean} [hideWhenNoResults=true] Hide the container when no results match
391+
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
390392
* @return {Object}
391393
*/
392394
```
@@ -429,7 +431,7 @@ search.addWidget(
429431
* @param {String|Function} [options.templates.header=''] Header template
430432
* @param {String|Function} [options.templates.item='<a href="{{href}}">{{name}}</a> {{count}}'] Item template, provided with `name`, `count`, `isRefined`
431433
* @param {String|Function} [options.templates.footer=''] Footer template
432-
* @param {boolean} [hideWhenNoResults=true] Hide the container when no results match
434+
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
433435
* @return {Object}
434436
*/
435437
```
@@ -466,6 +468,7 @@ search.addWidget(
466468
* You can also provide
467469
* tooltips: {format: function(formattedValue, rawValue) {return '$' + formattedValue}}
468470
* So that you can format the tooltip display value as you want
471+
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
469472
* @return {Object}
470473
*/
471474
```

components/IndexSelector.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
var React = require('react');
22

3+
var autoHide = require('../decorators/autoHide');
4+
35
class IndexSelector extends React.Component {
46
handleChange(event) {
57
this.props.setIndex(event.target.value).search();
@@ -34,4 +36,4 @@ IndexSelector.propTypes = {
3436
setIndex: React.PropTypes.func
3537
};
3638

37-
module.exports = IndexSelector;
39+
module.exports = autoHide(IndexSelector);

components/Pagination/Pagination.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ var Paginator = require('./Paginator');
66
var PaginationHiddenLink = require('./PaginationHiddenLink');
77
var PaginationLink = require('./PaginationLink');
88

9+
var autoHide = require('../../decorators/autoHide');
10+
911
var bem = require('../../lib/utils').bemHelper;
1012
var cx = require('classnames');
1113

@@ -99,10 +101,6 @@ class Pagination extends React.Component {
99101
}
100102

101103
render() {
102-
if (this.props.nbHits === 0) {
103-
return null;
104-
}
105-
106104
var pager = new Paginator({
107105
currentPage: this.props.currentPage,
108106
total: this.props.nbPages,
@@ -156,4 +154,4 @@ Pagination.defaultProps = {
156154
padding: 3
157155
};
158156

159-
module.exports = Pagination;
157+
module.exports = autoHide(Pagination);

components/RefinementList.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var React = require('react');
22

33
var Template = require('./Template');
4+
var autoHide = require('../decorators/autoHide');
45
var cx = require('classnames');
56

67
class RefinementList extends React.Component {
@@ -108,4 +109,4 @@ RefinementList.defaultProps = {
108109
}
109110
};
110111

111-
module.exports = RefinementList;
112+
module.exports = autoHide(RefinementList);

components/Slider/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var React = require('react');
22

33
var Nouislider = require('react-nouislider');
4+
var autoHide = require('../../decorators/autoHide');
45

56
require('style?prepend!raw!./index.css');
67

@@ -38,4 +39,4 @@ Slider.propTypes = {
3839
])
3940
};
4041

41-
module.exports = Slider;
42+
module.exports = autoHide(Slider);

components/Stats.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var React = require('react');
22

33
var Template = require('./Template');
4+
var autoHide = require('../decorators/autoHide');
45

56
class Stats extends React.Component {
67
render() {
@@ -42,4 +43,4 @@ Stats.propTypes = {
4243
query: React.PropTypes.string
4344
};
4445

45-
module.exports = Stats;
46+
module.exports = autoHide(Stats);

components/Toggle.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var React = require('react');
22

33
var Template = require('./Template');
4+
var autoHide = require('../decorators/autoHide');
45
var debounce = require('lodash/function/debounce');
56

67
class Toggle extends React.Component {
@@ -35,4 +36,4 @@ Toggle.propTypes = {
3536
isRefined: React.PropTypes.bool
3637
};
3738

38-
module.exports = Toggle;
39+
module.exports = autoHide(Toggle);

decorators/autoHide.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
var React = require('react');
2+
3+
function autoHide(ComposedComponent) {
4+
class AutoHide extends React.Component {
5+
componentDidMount() {
6+
this._hideOrShowContainer(this.props);
7+
}
8+
9+
componentWillReceiveProps(nextProps) {
10+
this._hideOrShowContainer(nextProps);
11+
}
12+
13+
_hideOrShowContainer(props) {
14+
var container = React.findDOMNode(this).parentNode;
15+
if (props.hideIfEmpty === true && props.hasResults === false) {
16+
container.style.display = 'none';
17+
} else if (props.hideIfEmpty === true) {
18+
container.style.display = '';
19+
}
20+
}
21+
22+
render() {
23+
if (this.props.hasResults === false &&
24+
this.props.hideIfEmpty === true) {
25+
return <div/>;
26+
}
27+
28+
return <ComposedComponent {...this.props} />;
29+
}
30+
}
31+
32+
AutoHide.propTypes = {
33+
hasResults: React.PropTypes.bool.isRequired,
34+
hideIfEmpty: React.PropTypes.bool.isRequired
35+
};
36+
37+
// precise displayName for ease of debugging (react dev tool, react warnings)
38+
AutoHide.displayName = ComposedComponent.name + '-AutoHide';
39+
40+
return AutoHide;
41+
}
42+
43+
module.exports = autoHide;

index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ var toFactory = require('to-factory');
33
var InstantSearch = require('./lib/InstantSearch');
44
var instantsearch = toFactory(InstantSearch);
55

6-
require('style?prepend!raw!./lib/style.css');
7-
86
instantsearch.widgets = {
97
hits: require('./widgets/hits'),
108
indexSelector: require('./widgets/index-selector'),

lib/style.css

Lines changed: 0 additions & 3 deletions
This file was deleted.

widgets/hits.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ var React = require('react');
22

33
var utils = require('../lib/utils.js');
44

5-
function hits({container = null, templates = {}, hitsPerPage = 20}) {
5+
function hits({
6+
container = null,
7+
templates = {},
8+
hitsPerPage = 20,
9+
hideIfEmpty = false
10+
}) {
611
var Hits = require('../components/Hits');
712

813
var containerNode = utils.getContainerNode(container);
@@ -16,6 +21,8 @@ function hits({container = null, templates = {}, hitsPerPage = 20}) {
1621
results={results}
1722
helper={helper}
1823
noResultsTemplate={templates.empty}
24+
hideIfEmpty={hideIfEmpty}
25+
hasResults={results.hits.length > 0}
1926
hitTemplate={templates.hit}
2027
/>,
2128
containerNode

widgets/index-selector.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ var utils = require('../lib/utils.js');
88
* @param {String|DOMElement} options.container Valid CSS Selector as a string or DOMElement
99
* @param {Array} options.indices Array of objects defining the different indices to choose from. Each object must contain a `name` and `label` key.
1010
* @param {String} [options.cssClass] Class name(s) to be added to the generated select element
11+
* @param {boolean} [hideIfEmpty=false] Hide the container when no results match
1112
* @return {Object}
1213
*/
1314
function indexSelector({
1415
container = null,
1516
indices = null,
16-
cssClass
17+
cssClass,
18+
hideIfEmpty = false
1719
}) {
1820
var IndexSelector = require('../components/IndexSelector');
1921
var containerNode = utils.getContainerNode(container);
@@ -32,14 +34,16 @@ function indexSelector({
3234
}
3335
},
3436

35-
render: function({helper}) {
37+
render: function({helper, results}) {
3638
var containerId = containerNode.id;
3739
React.render(
3840
<IndexSelector
3941
containerId={containerId}
4042
cssClass={cssClass}
4143
currentIndex={helper.getIndex()}
4244
indices={indices}
45+
hideIfEmpty={hideIfEmpty}
46+
hasResults={results.hits.length > 0}
4347
setIndex={helper.setIndex.bind(helper)}
4448
/>,
4549
containerNode

widgets/menu.js

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var defaults = require('lodash/object/defaults');
2828
* @param {String|Function} [options.templates.item='<a href="{{href}}">{{name}}</a> {{count}}'] Item template, provided with `name`, `count`, `isRefined`
2929
* @param {String|Function} [options.templates.footer=''] Footer template
3030
* @param {Function} [options.transformData] Method to change the object passed to the item template
31-
* @param {boolean} [hideWhenNoResults=true] Hide the container when no results match
31+
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
3232
* @return {Object}
3333
*/
3434
function menu({
@@ -41,7 +41,7 @@ function menu({
4141
list: null,
4242
item: null
4343
},
44-
hideWhenNoResults = true,
44+
hideIfEmpty = true,
4545
templates = defaultTemplates,
4646
transformData = null
4747
}) {
@@ -70,26 +70,16 @@ function menu({
7070
}]
7171
}),
7272
render: function({results, helper}) {
73-
var values = getFacetValues(results, hierarchicalFacetName, sortBy, limit);
74-
75-
if (values.length === 0) {
76-
React.render(<div/>, containerNode);
77-
if (hideWhenNoResults === true) {
78-
containerNode.classList.add('as-display-none');
79-
}
80-
return;
81-
}
82-
83-
if (hideWhenNoResults === true) {
84-
containerNode.classList.remove('as-display-none');
85-
}
73+
var facetValues = getFacetValues(results, hierarchicalFacetName, sortBy, limit);
8674

8775
React.render(
8876
<RefinementList
8977
cssClasses={cssClasses}
90-
facetValues={getFacetValues(results, hierarchicalFacetName, sortBy, limit)}
78+
facetValues={facetValues}
9179
templates={templates}
9280
transformData={transformData}
81+
hideIfEmpty={hideIfEmpty}
82+
hasResults={facetValues.length > 0}
9383
toggleRefinement={toggleRefinement.bind(null, helper, hierarchicalFacetName)}
9484
/>,
9585
containerNode

widgets/pagination.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ var React = require('react');
22

33
var utils = require('../lib/utils.js');
44

5-
function pagination({container, cssClass, labels, maxPages, showFirstLast} = {}) {
5+
function pagination({
6+
container = null,
7+
cssClass,
8+
labels,
9+
maxPages,
10+
showFirstLast,
11+
hideIfEmpty = true
12+
}) {
613
var Pagination = require('../components/Pagination/Pagination.js');
714

815
var containerNode = utils.getContainerNode(container);
@@ -21,6 +28,8 @@ function pagination({container, cssClass, labels, maxPages, showFirstLast} = {})
2128
nbPages={nbPages}
2229
setCurrentPage={helper.setCurrentPage.bind(helper)}
2330
cssClass={cssClass}
31+
hideIfEmpty={hideIfEmpty}
32+
hasResults={results.hits.length > 0}
2433
labels={labels}
2534
showFirstLast={showFirstLast}
2635
/>,

widgets/range-slider.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ var utils = require('../lib/utils.js');
1111
* You can also provide
1212
* tooltips: {format: function(formattedValue, rawValue) {return '$' + formattedValue}}
1313
* So that you can format the tooltip display value as you want
14+
* @param {boolean} [hideIfEmpty=true] Hide the container when no results match
1415
* @return {Object}
1516
*/
1617
function rangeSlider({
1718
container = null,
1819
facetName = null,
19-
tooltips = true
20+
tooltips = true,
21+
hideIfEmpty = true
2022
}) {
2123
var Slider = require('../components/Slider');
2224

@@ -58,15 +60,19 @@ function rangeSlider({
5860

5961
var currentRefinement = this._getCurrentRefinement(helper);
6062

61-
if (!stats) {
62-
React.render(<div/>, containerNode);
63-
return;
63+
if (stats === undefined) {
64+
stats = {
65+
min: null,
66+
max: null
67+
};
6468
}
6569

6670
React.render(
6771
<Slider
6872
start={[currentRefinement.min, currentRefinement.max]}
6973
range={{min: stats.min, max: stats.max}}
74+
hideIfEmpty={hideIfEmpty}
75+
hasResults={stats.min !== null && stats.max !== null}
7076
onChange={this._refine.bind(this, helper)}
7177
tooltips={tooltips}
7278
/>,

0 commit comments

Comments
 (0)