diff --git a/src/components/Slider/Slider.js b/src/components/Slider/Slider.js index afe87c7d67..d40f119160 100644 --- a/src/components/Slider/Slider.js +++ b/src/components/Slider/Slider.js @@ -35,14 +35,17 @@ class Slider extends Component { return this.props.min === this.props.max; } - handleChange = ({values}) => { + handleChange = ({min, max, values}) => { // when Slider is disabled, we alter `min, max` values // in order to render a "disabled state" Slider. Since we alter // theses values, Rheostat trigger a "change" event which trigger a new // search to Algolia with wrong values. if (!this.isDisabled) { const {refine} = this.props; - refine(values); + refine([ + min === values[0] ? undefined : values[0], + max === values[1] ? undefined : values[1], + ]); } } diff --git a/src/connectors/range-slider/connectRangeSlider.js b/src/connectors/range-slider/connectRangeSlider.js index 0088784091..e54f1ea2fc 100644 --- a/src/connectors/range-slider/connectRangeSlider.js +++ b/src/connectors/range-slider/connectRangeSlider.js @@ -119,14 +119,21 @@ export default function connectRangeSlider(renderFn) { init({helper, instantSearchInstance}) { this._refine = bounds => newValues => { - helper.clearRefinements(attributeName); - if (!bounds.min || newValues[0] > bounds.min) { - helper.addNumericRefinement(attributeName, '>=', formatToNumber(newValues[0])); + const currentValues = [ + helper.getNumericRefinement(attributeName, '>='), + helper.getNumericRefinement(attributeName, '<='), + ]; + + if (currentValues[0] !== newValues[0] || currentValues[1] !== newValues[1]) { + helper.clearRefinements(attributeName); + if (!bounds.min || newValues[0] > bounds.min) { + helper.addNumericRefinement(attributeName, '>=', formatToNumber(newValues[0])); + } + if (!bounds.max || newValues[1] < bounds.max) { + helper.addNumericRefinement(attributeName, '<=', formatToNumber(newValues[1])); + } + helper.search(); } - if (!bounds.max || newValues[1] < bounds.max) { - helper.addNumericRefinement(attributeName, '<=', formatToNumber(newValues[1])); - } - helper.search(); }; const stats = { diff --git a/src/lib/InstantSearch.js b/src/lib/InstantSearch.js index 8fc9c5ac0b..73a4ecc541 100644 --- a/src/lib/InstantSearch.js +++ b/src/lib/InstantSearch.js @@ -121,19 +121,27 @@ Usage: instantsearch({ ); if (this._searchFunction) { - this.helper = Object.create(helper); - this.helper.search = () => { - helper.setState(this.helper.state); - this._searchFunction(helper); + this._mainHelperSearch = helper.search.bind(helper); + helper.search = () => { + const helperSearchFunction = algoliasearchHelper( + { + addAlgoliaAgent: () => {}, + search: () => {}, + }, + helper.state.index, + helper.state + ); + helperSearchFunction.once('search', state => { + helper.overrideStateWithoutTriggeringChangeEvent(state); + this._mainHelperSearch(); + }); + this._searchFunction(helperSearchFunction); }; - this._init(helper.state, this.helper); - helper.on('result', this._render.bind(this, this.helper)); - } else { - this.helper = helper; - this._init(helper.state, this.helper); - this.helper.on('result', this._render.bind(this, this.helper)); } + this.helper = helper; + this._init(helper.state, this.helper); + this.helper.on('result', this._render.bind(this, this.helper)); this.helper.search(); } diff --git a/src/lib/__tests__/InstantSearch-test-2.js b/src/lib/__tests__/InstantSearch-test-2.js new file mode 100644 index 0000000000..00890660e7 --- /dev/null +++ b/src/lib/__tests__/InstantSearch-test-2.js @@ -0,0 +1,38 @@ +import sinon from 'sinon'; + +// import algoliaSearchHelper from 'algoliasearch-helper'; +import InstantSearch from '../InstantSearch'; + +const appId = 'appId'; +const apiKey = 'apiKey'; +const indexName = 'lifecycle'; + +describe.only('InstantSearch lifecycle', () => { + it('calls the provided searchFunction when used', () => { + const searchFunctionSpy = sinon.spy(h => { + h.setQuery('test').search(); + }); + + const fakeClient = { + search: sinon.spy(), + addAlgoliaAgent: () => {}, + }; + + const search = new InstantSearch({ + appId, + apiKey, + indexName, + searchFunction: searchFunctionSpy, + createAlgoliaClient: () => fakeClient, + }); + + expect(searchFunctionSpy.callCount).toBe(0); + expect(fakeClient.search.callCount).toBe(0); + + search.start(); + + expect(searchFunctionSpy.callCount).toBe(1); + expect(search.helper.state.query).toBe('test'); + expect(fakeClient.search.callCount).toBe(1); + }); +}); diff --git a/src/lib/__tests__/InstantSearch-test.js b/src/lib/__tests__/InstantSearch-test.js index 9cd8d437e8..e1e75d5621 100644 --- a/src/lib/__tests__/InstantSearch-test.js +++ b/src/lib/__tests__/InstantSearch-test.js @@ -125,22 +125,6 @@ describe('InstantSearch lifecycle', () => { }); }); - it('calls the provided searchFunction when used', () => { - const searchSpy = sinon.spy(h => { - h.setQuery('test').search(); - }); - search = new InstantSearch({ - appId, - apiKey, - indexName, - searchFunction: searchSpy, - }); - search.start(); - expect(searchSpy.calledOnce).toBe(true); - expect(helper.state.query).toBe('test'); - expect(helperSearchSpy.calledOnce).toBe(true); - }); - it('does not fail when passing same references inside multiple searchParameters props', () => { const disjunctiveFacetsRefinements = {fruits: ['apple']}; const facetsRefinements = disjunctiveFacetsRefinements;