Skip to content

Commit

Permalink
feat(rangeSlider): allow passing min and max values
Browse files Browse the repository at this point in the history
fixes #858
  • Loading branch information
vvo committed Mar 3, 2016
1 parent 081d6a3 commit 409295c
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 11 deletions.
2 changes: 2 additions & 0 deletions dev/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ search.addWidget(
templates: {
header: 'Price'
},
min: 100,
max: 500,
step: 10,
tooltips: {
format: function(formattedValue) {
Expand Down
85 changes: 83 additions & 2 deletions src/widgets/range-slider/__tests__/range-slider-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ describe('rangeSlider()', () => {
rangeSlider.__Rewire__('headerFooterHOC', headerFooter);

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

helper = new AlgoliasearchHelper(
{search: function() {}},
Expand All @@ -58,12 +57,90 @@ describe('rangeSlider()', () => {
sinon.spy(helper, 'addNumericRefinement');
sinon.spy(helper, 'clearRefinements');
sinon.spy(helper, 'search');
widget.init({helper});
});

context('min option', () => {
it('refines when no previous configuration', () => {
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100});
expect(widget.getConfiguration()).toEqual({
disjunctiveFacets: ['aNumAttr'],
numericRefinements: {aNumAttr: {'>=': [100]}}
});
});

it('does not refine when previous configuration', () => {
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100});
expect(widget.getConfiguration({numericRefinements: {aNumAttr: {}}})).toEqual({
disjunctiveFacets: ['aNumAttr']
});
});

it('works along with max option', () => {
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100, max: 200});
expect(widget.getConfiguration()).toEqual({
disjunctiveFacets: ['aNumAttr'],
numericRefinements: {aNumAttr: {'>=': [100], '<=': [200]}}
});
});

it('sets the right ranges', () => {
results = {};
widget = rangeSlider({container, attributeName: 'aNumAttr', min: 100, max: 200});
helper.setState(widget.getConfiguration());
widget.init({helper});
widget.render({results, helper});
let props = {
cssClasses: {
root: 'ais-range-slider',
header: 'ais-range-slider--header',
body: 'ais-range-slider--body',
footer: 'ais-range-slider--footer'
},
collapsible: false,
onChange: () => {},
pips: true,
range: {max: 200, min: 100},
shouldAutoHideContainer: false,
start: [100, 200],
step: 1,
templateProps: {
templates: {footer: '', header: ''},
templatesConfig: undefined,
transformData: undefined,
useCustomCompileOptions: {footer: false, header: false}
},
tooltips: true
};

expect(ReactDOM.render.calledOnce).toBe(true, 'ReactDOM.render called once');
expect(autoHideContainer.calledOnce).toBe(true, 'autoHideContainer called once');
expect(headerFooter.calledOnce).toBe(true, 'headerFooter called once');
expect(ReactDOM.render.firstCall.args[0]).toEqualJSX(<Slider {...props} />);
});
});

context('max option', () => {
it('refines when no previous configuration', () => {
widget = rangeSlider({container, attributeName: 'aNumAttr', max: 100});
expect(widget.getConfiguration()).toEqual({
disjunctiveFacets: ['aNumAttr'],
numericRefinements: {aNumAttr: {'<=': [100]}}
});
});

it('does not refine when previous configuration', () => {
widget = rangeSlider({container, attributeName: 'aNumAttr', max: 100});
expect(widget.getConfiguration({numericRefinements: {aNumAttr: {}}})).toEqual({
disjunctiveFacets: ['aNumAttr']
});
});
});

context('without result', () => {
beforeEach(() => {
results = {};
widget = rangeSlider({container, attributeName: 'aNumAttr', cssClasses: {root: ['root', 'cx']}});
widget.init({helper});
});

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

context('when rangestats min === stats max', () => {
beforeEach(() => {
widget = rangeSlider({container, attributeName: 'aNumAttr', cssClasses: {root: ['root', 'cx']}});
widget.init({helper});
results = {
disjunctiveFacets: [{
name: 'aNumAttr',
Expand Down Expand Up @@ -150,6 +229,8 @@ describe('rangeSlider()', () => {

context('with results', () => {
beforeEach(() => {
widget = rangeSlider({container, attributeName: 'aNumAttr', cssClasses: {root: ['root', 'cx']}});
widget.init({helper});
results = {
disjunctiveFacets: [{
name: 'aNumAttr',
Expand Down
57 changes: 48 additions & 9 deletions src/widgets/range-slider/range-slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ let defaultTemplates = {
* @param {string|string[]} [options.cssClasses.footer] CSS class to add to the footer element
* @param {object|boolean} [options.collapsible=false] Hide the widget body and footer when clicking on header
* @param {boolean} [options.collapsible.collapsed] Initial collapsed state of a collapsible widget
* @param {number} [options.min] Minimal slider value, default to automatically computed from the result set
* @param {number} [options.max] Maximal slider value, defaults to automatically computed from the result set
* @return {Object}
*/
const usage = `Usage:
Expand All @@ -50,7 +52,9 @@ rangeSlider({
[ step=1 ],
[ pips=true ],
[ autoHideContainer=true ],
[ collapsible=false ]
[ collapsible=false ],
[ min ],
[ max ]
});
`;
function rangeSlider({
Expand All @@ -62,7 +66,9 @@ function rangeSlider({
cssClasses: userCssClasses = {},
step = 1,
pips = true,
autoHideContainer = true
autoHideContainer = true,
min: userMin,
max: userMax
} = {}) {
if (!container || !attributeName) {
throw new Error(usage);
Expand All @@ -82,9 +88,31 @@ function rangeSlider({
};

return {
getConfiguration: () => ({
disjunctiveFacets: [attributeName]
}),
getConfiguration: (originalConf) => {
const conf = {
disjunctiveFacets: [attributeName]
};

if (
(userMin !== undefined || userMax !== undefined)
&&
(!originalConf ||
originalConf.numericRefinements &&
originalConf.numericRefinements[attributeName] === undefined)
) {
conf.numericRefinements = {[attributeName]: {}};

if (userMin !== undefined) {
conf.numericRefinements[attributeName]['>='] = [userMin];
}

if (userMax !== undefined) {
conf.numericRefinements[attributeName]['<='] = [userMax];
}
}

This comment has been minimized.

Copy link
@redox

redox Mar 11, 2016

Contributor

I always find it more convenient to do those initial refinements from the init({helper}) function. Part of that, can it have any negative impact to it here @bobylito?

I did https://github.com/instantsearch/instantsearch-ion.rangeSlider/blob/5acdf43f375c369a56f092fca33f0a3ba1daa6de/src/widget.js#L39-L48

cc @vvo

This comment has been minimized.

Copy link
@vvo

vvo Mar 11, 2016

Contributor

Not sure also if there's a benefit/drawbacks doing it in getConfiguration or init.


return conf;
},
_getCurrentRefinement(helper) {
let min = helper.state.getNumericRefinement(attributeName, '>=');
let max = helper.state.getNumericRefinement(attributeName, '<=');
Expand Down Expand Up @@ -125,16 +153,27 @@ function rangeSlider({
},
render({results, helper}) {
let facet = find(results.disjunctiveFacets, {name: attributeName});
let stats = facet !== undefined ? facet.stats : undefined;
let currentRefinement = this._getCurrentRefinement(helper);
let stats;

if (userMin !== undefined || userMax !== undefined) {
stats = {};

if (userMin !== undefined) {
stats.min = userMin;
}

if (stats === undefined) {
stats = {
if (userMax !== undefined) {
stats.max = userMax;
}
} else {
stats = facet !== undefined && facet.stats !== undefined ? facet.stats : {
min: null,
max: null
};
}

let currentRefinement = this._getCurrentRefinement(helper);

if (tooltips.format !== undefined) {
tooltips = [{to: tooltips.format}, {to: tooltips.format}];
}
Expand Down

0 comments on commit 409295c

Please sign in to comment.