Skip to content

Commit 409295c

Browse files
author
vvo
committed
feat(rangeSlider): allow passing min and max values
fixes #858
1 parent 081d6a3 commit 409295c

File tree

3 files changed

+133
-11
lines changed

3 files changed

+133
-11
lines changed

dev/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ search.addWidget(
277277
templates: {
278278
header: 'Price'
279279
},
280+
min: 100,
281+
max: 500,
280282
step: 10,
281283
tooltips: {
282284
format: function(formattedValue) {

src/widgets/range-slider/__tests__/range-slider-test.js

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ describe('rangeSlider()', () => {
4848
rangeSlider.__Rewire__('headerFooterHOC', headerFooter);
4949

5050
container = document.createElement('div');
51-
widget = rangeSlider({container, attributeName: 'aNumAttr', cssClasses: {root: ['root', 'cx']}});
5251

5352
helper = new AlgoliasearchHelper(
5453
{search: function() {}},
@@ -58,12 +57,90 @@ describe('rangeSlider()', () => {
5857
sinon.spy(helper, 'addNumericRefinement');
5958
sinon.spy(helper, 'clearRefinements');
6059
sinon.spy(helper, 'search');
61-
widget.init({helper});
60+
});
61+
62+
context('min option', () => {
63+
it('refines when no previous configuration', () => {
64+
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100});
65+
expect(widget.getConfiguration()).toEqual({
66+
disjunctiveFacets: ['aNumAttr'],
67+
numericRefinements: {aNumAttr: {'>=': [100]}}
68+
});
69+
});
70+
71+
it('does not refine when previous configuration', () => {
72+
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100});
73+
expect(widget.getConfiguration({numericRefinements: {aNumAttr: {}}})).toEqual({
74+
disjunctiveFacets: ['aNumAttr']
75+
});
76+
});
77+
78+
it('works along with max option', () => {
79+
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100, max: 200});
80+
expect(widget.getConfiguration()).toEqual({
81+
disjunctiveFacets: ['aNumAttr'],
82+
numericRefinements: {aNumAttr: {'>=': [100], '<=': [200]}}
83+
});
84+
});
85+
86+
it('sets the right ranges', () => {
87+
results = {};
88+
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100, max: 200});
89+
helper.setState(widget.getConfiguration());
90+
widget.init({helper});
91+
widget.render({results, helper});
92+
let props = {
93+
cssClasses: {
94+
root: 'ais-range-slider',
95+
header: 'ais-range-slider--header',
96+
body: 'ais-range-slider--body',
97+
footer: 'ais-range-slider--footer'
98+
},
99+
collapsible: false,
100+
onChange: () => {},
101+
pips: true,
102+
range: {max: 200, min: 100},
103+
shouldAutoHideContainer: false,
104+
start: [100, 200],
105+
step: 1,
106+
templateProps: {
107+
templates: {footer: '', header: ''},
108+
templatesConfig: undefined,
109+
transformData: undefined,
110+
useCustomCompileOptions: {footer: false, header: false}
111+
},
112+
tooltips: true
113+
};
114+
115+
expect(ReactDOM.render.calledOnce).toBe(true, 'ReactDOM.render called once');
116+
expect(autoHideContainer.calledOnce).toBe(true, 'autoHideContainer called once');
117+
expect(headerFooter.calledOnce).toBe(true, 'headerFooter called once');
118+
expect(ReactDOM.render.firstCall.args[0]).toEqualJSX(<Slider {...props} />);
119+
});
120+
});
121+
122+
context('max option', () => {
123+
it('refines when no previous configuration', () => {
124+
widget = rangeSlider({container, attributeName: 'aNumAttr', max: 100});
125+
expect(widget.getConfiguration()).toEqual({
126+
disjunctiveFacets: ['aNumAttr'],
127+
numericRefinements: {aNumAttr: {'<=': [100]}}
128+
});
129+
});
130+
131+
it('does not refine when previous configuration', () => {
132+
widget = rangeSlider({container, attributeName: 'aNumAttr', max: 100});
133+
expect(widget.getConfiguration({numericRefinements: {aNumAttr: {}}})).toEqual({
134+
disjunctiveFacets: ['aNumAttr']
135+
});
136+
});
62137
});
63138

64139
context('without result', () => {
65140
beforeEach(() => {
66141
results = {};
142+
widget = rangeSlider({container, attributeName: 'aNumAttr', cssClasses: {root: ['root', 'cx']}});
143+
widget.init({helper});
67144
});
68145

69146
it('calls ReactDOM.render(<Slider props />, container)', () => {
@@ -101,6 +178,8 @@ describe('rangeSlider()', () => {
101178

102179
context('when rangestats min === stats max', () => {
103180
beforeEach(() => {
181+
widget = rangeSlider({container, attributeName: 'aNumAttr', cssClasses: {root: ['root', 'cx']}});
182+
widget.init({helper});
104183
results = {
105184
disjunctiveFacets: [{
106185
name: 'aNumAttr',
@@ -150,6 +229,8 @@ describe('rangeSlider()', () => {
150229

151230
context('with results', () => {
152231
beforeEach(() => {
232+
widget = rangeSlider({container, attributeName: 'aNumAttr', cssClasses: {root: ['root', 'cx']}});
233+
widget.init({helper});
153234
results = {
154235
disjunctiveFacets: [{
155236
name: 'aNumAttr',

src/widgets/range-slider/range-slider.js

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ let defaultTemplates = {
3838
* @param {string|string[]} [options.cssClasses.footer] CSS class to add to the footer element
3939
* @param {object|boolean} [options.collapsible=false] Hide the widget body and footer when clicking on header
4040
* @param {boolean} [options.collapsible.collapsed] Initial collapsed state of a collapsible widget
41+
* @param {number} [options.min] Minimal slider value, default to automatically computed from the result set
42+
* @param {number} [options.max] Maximal slider value, defaults to automatically computed from the result set
4143
* @return {Object}
4244
*/
4345
const usage = `Usage:
@@ -50,7 +52,9 @@ rangeSlider({
5052
[ step=1 ],
5153
[ pips=true ],
5254
[ autoHideContainer=true ],
53-
[ collapsible=false ]
55+
[ collapsible=false ],
56+
[ min ],
57+
[ max ]
5458
});
5559
`;
5660
function rangeSlider({
@@ -62,7 +66,9 @@ function rangeSlider({
6266
cssClasses: userCssClasses = {},
6367
step = 1,
6468
pips = true,
65-
autoHideContainer = true
69+
autoHideContainer = true,
70+
min: userMin,
71+
max: userMax
6672
} = {}) {
6773
if (!container || !attributeName) {
6874
throw new Error(usage);
@@ -82,9 +88,31 @@ function rangeSlider({
8288
};
8389

8490
return {
85-
getConfiguration: () => ({
86-
disjunctiveFacets: [attributeName]
87-
}),
91+
getConfiguration: (originalConf) => {
92+
const conf = {
93+
disjunctiveFacets: [attributeName]
94+
};
95+
96+
if (
97+
(userMin !== undefined || userMax !== undefined)
98+
&&
99+
(!originalConf ||
100+
originalConf.numericRefinements &&
101+
originalConf.numericRefinements[attributeName] === undefined)
102+
) {
103+
conf.numericRefinements = {[attributeName]: {}};
104+
105+
if (userMin !== undefined) {
106+
conf.numericRefinements[attributeName]['>='] = [userMin];
107+
}
108+
109+
if (userMax !== undefined) {
110+
conf.numericRefinements[attributeName]['<='] = [userMax];
111+
}
112+
}
113+
114+
return conf;
115+
},
88116
_getCurrentRefinement(helper) {
89117
let min = helper.state.getNumericRefinement(attributeName, '>=');
90118
let max = helper.state.getNumericRefinement(attributeName, '<=');
@@ -125,16 +153,27 @@ function rangeSlider({
125153
},
126154
render({results, helper}) {
127155
let facet = find(results.disjunctiveFacets, {name: attributeName});
128-
let stats = facet !== undefined ? facet.stats : undefined;
129-
let currentRefinement = this._getCurrentRefinement(helper);
156+
let stats;
157+
158+
if (userMin !== undefined || userMax !== undefined) {
159+
stats = {};
160+
161+
if (userMin !== undefined) {
162+
stats.min = userMin;
163+
}
130164

131-
if (stats === undefined) {
132-
stats = {
165+
if (userMax !== undefined) {
166+
stats.max = userMax;
167+
}
168+
} else {
169+
stats = facet !== undefined && facet.stats !== undefined ? facet.stats : {
133170
min: null,
134171
max: null
135172
};
136173
}
137174

175+
let currentRefinement = this._getCurrentRefinement(helper);
176+
138177
if (tooltips.format !== undefined) {
139178
tooltips = [{to: tooltips.format}, {to: tooltips.format}];
140179
}

0 commit comments

Comments
 (0)