Skip to content

Commit

Permalink
fix(url-sync): Makes url sync more reliable
Browse files Browse the repository at this point in the history
2 main changes here :
 - the url-sync internal widget now relies on the helper directly and
   not on the instantsearch lifecycle anymore.
 - there is dedicated channel of update for the changes coming from the
   history (private API for the moment)

FIX #730
FIX #729
  • Loading branch information
Alexandre Stanislawski committed Jan 19, 2016
1 parent 7d1d03a commit 3157abc
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 61 deletions.
5 changes: 2 additions & 3 deletions dev/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ var search = instantsearch({
appId: 'latency',
apiKey: '6be0576ff61c053d5f9a3225e2a90f76',
indexName: 'instant_search',
urlSync: {
useHash: true
}
urlSync: true
});

search.addWidget(
Expand Down Expand Up @@ -281,3 +279,4 @@ search.addWidget(
);

search.start();

17 changes: 11 additions & 6 deletions src/lib/InstantSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import forEach from 'lodash/collection/forEach';
import merge from 'lodash/object/merge';
import union from 'lodash/array/union';

let EventEmitter = require('events').EventEmitter;
import {EventEmitter} from 'events';

import urlSyncWidget from './url-sync.js';
import version from './version.js';
Expand All @@ -20,7 +20,8 @@ function defaultCreateURL() { return '#'; }
* @param {string} [options.numberLocale] The locale used to display numbers. This will be passed
* to Number.prototype.toLocaleString()
* @param {Object} [options.searchParameters] Additional parameters to pass to
* the Algolia API. [Full documentation](https://community.algolia.com/algoliasearch-helper-js/docs/SearchParameters.html)
* the Algolia API.
* [Full documentation](https://community.algolia.com/algoliasearch-helper-js/docs/SearchParameters.html)
* @param {Object|boolean} [options.urlSync] Url synchronization configuration.
* Setting to `true` will synchronize the needed search parameters with the browser url.
* @param {string[]} [options.urlSync.trackedParameters] Parameters that will
Expand Down Expand Up @@ -66,7 +67,7 @@ Usage: instantsearch({
helpers: require('./helpers.js')({numberLocale}),
compileOptions: {}
};
this.urlSync = urlSync;
this.urlSync = urlSync === true ? {} : urlSync;
}

/**
Expand All @@ -93,8 +94,12 @@ Usage: instantsearch({
if (this.urlSync) {
let syncWidget = urlSyncWidget(this.urlSync);
this._createURL = syncWidget.createURL.bind(syncWidget);
this._onHistoryChange = syncWidget.onHistoryChange.bind(syncWidget);
this.widgets.push(syncWidget);
} else this._createURL = defaultCreateURL;
} else {
this._createURL = defaultCreateURL;
this._onHistoryChange = function() {};
}

this.searchParameters = this.widgets.reduce(enhanceConfiguration, this.searchParameters);

Expand Down Expand Up @@ -136,10 +141,10 @@ Usage: instantsearch({
}

_init(state, helper) {
const {_onHistoryChange, templatesConfig} = this;
forEach(this.widgets, function(widget) {
if (widget.init) {
const templatesConfig = this.templatesConfig;
widget.init({state, helper, templatesConfig});
widget.init({state, helper, templatesConfig, onHistoryChange: _onHistoryChange});
}
}, this);
}
Expand Down
25 changes: 17 additions & 8 deletions src/lib/__tests__/InstantSearch-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ describe('InstantSearch lifecycle', () => {
apiKey = 'apiKey';
indexName = 'lifecycle';

searchParameters = {some: 'configuration', values: [-2, -1], index: indexName, another: {config: 'parameter'}};
searchParameters = {
some: 'configuration',
values: [-2, -1],
index: indexName,
another: {config: 'parameter'}
};

InstantSearch.__Rewire__('algoliasearch', algoliasearch);
InstantSearch.__Rewire__('algoliasearchHelper', algoliasearchHelper);
Expand Down Expand Up @@ -113,7 +118,12 @@ describe('InstantSearch lifecycle', () => {
.toEqual([
client,
indexName,
{some: 'modified', values: [-2, -1], index: indexName, another: {different: 'parameter', config: 'parameter'}}
{
some: 'modified',
values: [-2, -1],
index: indexName,
another: {different: 'parameter', config: 'parameter'}
}
]);
});

Expand All @@ -125,12 +135,11 @@ describe('InstantSearch lifecycle', () => {
expect(widget.init.calledOnce).toBe(true, 'widget.init called once');
expect(widget.init.calledAfter(widget.getConfiguration))
.toBe(true, 'widget.init() was called after widget.getConfiguration()');
expect(widget.init.args[0][0]).
toEqual({
state: helper.state,
helper,
templatesConfig: search.templatesConfig
});
const args = widget.init.args[0][0];
expect(args.state).toBe(helper.state);
expect(args.helper).toBe(helper);
expect(args.templatesConfig).toBe(search.templatesConfig);
expect(args.onHistoryChange).toBe(search._onHistoryChange);
});

it('does not call widget.render', () => {
Expand Down
44 changes: 27 additions & 17 deletions src/lib/url-sync.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import algoliasearchHelper from 'algoliasearch-helper';
let AlgoliaSearchHelper = algoliasearchHelper.AlgoliaSearchHelper;
let majorVersionNumber = require('../lib/version.js').split('.')[0];
import urlHelper from 'algoliasearch-helper/src/url';

import isEqual from 'lodash/lang/isEqual';
import merge from 'lodash/object/merge';
Expand Down Expand Up @@ -104,42 +105,42 @@ class URLSync {
return config;
}

onPopState(helper) {
let qs = this.urlUtils.readUrl();
let partialState = AlgoliaSearchHelper.getConfigurationFromQueryString(qs);
let fullState = merge({}, this.originalConfig, partialState);
init({helper}) {
helper.on('change', (state) => {
this.renderURLFromState(state);
});
this.onHistoryChange(this.onPopState.bind(this, helper));
}

onPopState(helper, fullState) {
// compare with helper.state
let partialHelperState = helper.getState(this.trackedParameters);
let fullHelperState = merge({}, this.originalConfig, partialHelperState);

if (isEqual(fullHelperState, fullState)) return;

helper.setState(fullState).search();
helper.overrideStateWithoutTriggeringChangeEvent(fullState).search();
}

init({helper}) {
this.urlUtils.onpopstate(this.onPopState.bind(this, helper));
}

render({helper}) {
let helperState = helper.getState(this.trackedParameters);
renderURLFromState(state) {
let currentQueryString = this.urlUtils.readUrl();
let urlState = AlgoliaSearchHelper.getConfigurationFromQueryString(currentQueryString);

if (isEqual(helperState, urlState)) return;

// Add instantsearch version to reconciliate old url with newer versions
let foreignConfig = AlgoliaSearchHelper.getForeignConfigurationInQueryString(currentQueryString);
foreignConfig.is_v = majorVersionNumber;

let qs = helper.getStateAsQueryString({filters: this.trackedParameters, moreAttributes: foreignConfig});
let qs = urlHelper.getQueryStringFromState(
state.filter(this.trackedParameters),
{moreAttributes: foreignConfig}
);

if (this.timer() < this.threshold) {
this.urlUtils.replaceState(qs);
} else {
this.urlUtils.pushState(qs);
}
}

// External API's

createURL(state) {
let currentQueryString = this.urlUtils.readUrl();
let filteredState = state.filter(this.trackedParameters);
Expand All @@ -149,6 +150,15 @@ class URLSync {

return this.urlUtils.createURL(algoliasearchHelper.url.getQueryStringFromState(filteredState));
}

onHistoryChange(fn) {
this.urlUtils.onpopstate(() => {
let qs = this.urlUtils.readUrl();
let partialState = AlgoliaSearchHelper.getConfigurationFromQueryString(qs);
let fullState = merge({}, this.originalConfig, partialState);
fn(fullState);
});
}
}

/**
Expand Down
Loading

0 comments on commit 3157abc

Please sign in to comment.