Skip to content

Commit 72655ab

Browse files
author
Alexandre Stanislawski
committed
fix(refinementList): reimplement show more on refinement list
1 parent 70aae51 commit 72655ab

File tree

4 files changed

+65
-21
lines changed

4 files changed

+65
-21
lines changed

src/components/RefinementList/RefinementList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,12 @@ RawRefinementList.propTypes = {
182182
}),
183183
depth: React.PropTypes.number,
184184
facetValues: React.PropTypes.array,
185-
showMore: React.PropTypes.bool,
186185
templateProps: React.PropTypes.object.isRequired,
187186
toggleRefinement: React.PropTypes.func.isRequired,
188187
searchFacetValues: React.PropTypes.func,
189188
searchPlaceholder: React.PropTypes.string,
190189
isFromSearch: React.PropTypes.bool,
190+
showMore: React.PropTypes.bool,
191191
toggleShowMore: React.PropTypes.func,
192192
isShowingMore: React.PropTypes.bool,
193193
};

src/connectors/menu/connectMenu.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,6 @@ export default function connectMenu(renderFn) {
162162
.toggleRefinement(attributeName, facetValue)
163163
.search();
164164

165-
this._helper = helper;
166-
167165
renderFn({
168166
items: [],
169167
createURL: this._createURL,

src/connectors/refinement-list/connectRefinementList.js

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ var customRefinementList = connectRefinementList(function render(params) {
1010
// searchForItems,
1111
// instantSearchInstance,
1212
// canRefine,
13+
// toggleShowMore,
14+
// isShowingMore,
1315
// widgetParams,
1416
// }
1517
});
@@ -18,17 +20,20 @@ search.addWidget(
1820
attributeName,
1921
[ operator = 'or' ],
2022
[ limit ],
23+
[ showMoreLimit ],
2124
[ sortBy = ['isRefined', 'count:desc', 'name:asc']],
2225
})
2326
);
2427
Full documentation available at https://community.algolia.com/instantsearch.js/connectors/connectRefinementList.html
2528
`;
2629

27-
export const checkUsage = ({attributeName, operator, usageMessage}) => {
30+
export const checkUsage = ({attributeName, operator, usageMessage, showMoreLimit, limit}) => {
2831
const noAttributeName = attributeName === undefined;
2932
const invalidOperator = !(/^(and|or)$/).test(operator);
33+
const invalidShowMoreLimit = showMoreLimit !== undefined ?
34+
isNaN(showMoreLimit) || showMoreLimit < limit : false;
3035

31-
if (noAttributeName || invalidOperator) {
36+
if (noAttributeName || invalidOperator || invalidShowMoreLimit) {
3237
throw new Error(usageMessage);
3338
}
3439
};
@@ -45,7 +50,10 @@ export const checkUsage = ({attributeName, operator, usageMessage}) => {
4550
* @typedef {Object} CustomRefinementListWidgetOptions
4651
* @property {string} attributeName The name of the attribute in the records.
4752
* @property {"and"|"or"} [operator = 'or'] How the filters are combined together.
48-
* @property {number} [limit = undefined] The max number of items to display.
53+
* @property {number} [limit = undefined] The max number of items to display when
54+
* `showMoreLimit` is not or if the widget is showing less value.
55+
* @property {number} [showMoreLimit] The max number of items to display if the widget
56+
* is showing more items.
4957
* @property {string[]|function} [sortBy = ['isRefined', 'count:desc', 'name:asc']] How to sort refinements. Possible values: `count|isRefined|name:asc|name:desc`.
5058
*/
5159

@@ -58,14 +66,16 @@ export const checkUsage = ({attributeName, operator, usageMessage}) => {
5866
* @property {boolean} isFromSearch `true` if the values are from an index search.
5967
* @property {boolean} canRefine `true` if a refinement can be applied.
6068
* @property {Object} widgetParams All original `CustomRefinementListWidgetOptions` forwarded to the `renderFn`.
69+
* @property {boolean} isShowingMore True if the menu is displaying all the menu items.
70+
* @property {function} toggleShowMore Toggles the number of values displayed between `limit` and `showMoreLimit`.
6171
*/
6272

6373
/**
6474
* **RefinementList** connector provides the logic to build a custom widget that will let the
6575
* user filter the results based on the values of a specific facet.
6676
*
67-
* The connector provides to the rendering: `refine()` to select a value and
68-
* `items` that are the values that can be selected.
77+
* This connector provides a `toggleShowMore()` function to display more or less items and a `refine()`
78+
* function to select an item.
6979
* @type {Connector}
7080
* @param {function(RefinementListRenderingOptions, boolean)} renderFn Rendering function for the custom **RefinementList** widget.
7181
* @return {function(CustomRefinementListWidgetOptions)} Re-usable widget factory for a custom **RefinementList** widget.
@@ -123,17 +133,20 @@ export default function connectRefinementList(renderFn) {
123133
attributeName,
124134
operator = 'or',
125135
limit,
136+
showMoreLimit,
126137
sortBy = ['isRefined', 'count:desc', 'name:asc'],
127138
} = widgetParams;
128139

129-
checkUsage({attributeName, operator, usage});
140+
checkUsage({attributeName, operator, usage, limit, showMoreLimit});
130141

131142
const formatItems = ({name: label, ...item}) =>
132143
({...item, label, value: label, highlighted: label});
133144

134145
const render = ({items, state, createURL,
135146
helperSpecializedSearchFacetValues,
136-
refine, isFromSearch, isFirstSearch, instantSearchInstance}) => {
147+
refine, isFromSearch, isFirstSearch,
148+
isShowingMore, toggleShowMore,
149+
instantSearchInstance}) => {
137150
// Compute a specific createURL method able to link to any facet value state change
138151
const _createURL = facetValue => createURL(state.toggleRefinement(attributeName, facetValue));
139152

@@ -157,6 +170,8 @@ export default function connectRefinementList(renderFn) {
157170
isFromSearch,
158171
canRefine: isFromSearch || items.length > 0,
159172
widgetParams,
173+
isShowingMore,
174+
toggleShowMore,
160175
}, isFirstSearch);
161176
};
162177

@@ -198,19 +213,43 @@ export default function connectRefinementList(renderFn) {
198213
};
199214

200215
return {
216+
isShowingMore: false,
217+
218+
// Provide the same function to the `renderFn` so that way the user
219+
// has to only bind it once when `isFirstRendering` for instance
220+
toggleShowMore() {},
221+
cachedToggleShowMore() { this.toggleShowMore(); },
222+
223+
createToggleShowMore(renderOptions) {
224+
return () => {
225+
this.isShowingMore = !this.isShowingMore;
226+
this.render(renderOptions);
227+
};
228+
},
229+
230+
getLimit() {
231+
return this.isShowingMore ? showMoreLimit : limit;
232+
},
233+
201234
getConfiguration: (configuration = {}) => {
202235
const widgetConfiguration = {
203236
[operator === 'and' ? 'facets' : 'disjunctiveFacets']: [attributeName],
204237
};
205238

206239
if (limit !== undefined) {
207240
const currentMaxValuesPerFacet = configuration.maxValuesPerFacet || 0;
208-
widgetConfiguration.maxValuesPerFacet = Math.max(currentMaxValuesPerFacet, limit);
241+
if (showMoreLimit === undefined) {
242+
widgetConfiguration.maxValuesPerFacet = Math.max(currentMaxValuesPerFacet, limit);
243+
} else {
244+
widgetConfiguration.maxValuesPerFacet = Math.max(currentMaxValuesPerFacet, limit, showMoreLimit);
245+
}
209246
}
210247

211248
return widgetConfiguration;
212249
},
213250
init({helper, createURL, instantSearchInstance}) {
251+
this.cachedToggleShowMore = this.cachedToggleShowMore.bind(this);
252+
214253
refine = facetValue => helper
215254
.toggleRefinement(attributeName, facetValue)
216255
.search();
@@ -226,15 +265,21 @@ export default function connectRefinementList(renderFn) {
226265
isFromSearch: false,
227266
isFirstSearch: true,
228267
instantSearchInstance,
268+
isShowingMore: this.isShowingMore,
269+
toggleShowMore: this.cachedToggleShowMore,
229270
});
230271
},
231-
render({results, state, createURL, instantSearchInstance}) {
272+
render(renderOptions) {
273+
const {results, state, createURL, instantSearchInstance} = renderOptions;
232274
const items = results
233275
.getFacetValues(attributeName, {sortBy})
276+
.slice(0, this.getLimit())
234277
.map(formatItems);
235278

236279
lastResultsFromMainSearch = items;
237280

281+
this.toggleShowMore = this.createToggleShowMore(renderOptions);
282+
238283
render({
239284
items,
240285
state,
@@ -244,6 +289,8 @@ export default function connectRefinementList(renderFn) {
244289
isFromSearch: false,
245290
isFirstSearch: false,
246291
instantSearchInstance,
292+
isShowingMore: this.isShowingMore,
293+
toggleShowMore: this.cachedToggleShowMore,
247294
});
248295
},
249296
};

src/widgets/refinement-list/refinement-list.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ const renderer = ({
2424
templates,
2525
renderState,
2626
collapsible,
27-
limitMax,
28-
limit,
2927
autoHideContainer,
3028
showMoreConfig,
3129
searchForFacetValues,
@@ -37,6 +35,8 @@ const renderer = ({
3735
isFromSearch,
3836
instantSearchInstance,
3937
canRefine,
38+
toggleShowMore,
39+
isShowingMore,
4040
}, isFirstRendering) => {
4141
if (isFirstRendering) {
4242
renderState.templateProps = prepareTemplateProps({
@@ -60,15 +60,15 @@ const renderer = ({
6060
cssClasses={cssClasses}
6161
facetValues={items}
6262
headerFooterData={headerFooterData}
63-
limitMax={limitMax}
64-
limitMin={limit}
6563
shouldAutoHideContainer={autoHideContainer && canRefine === false}
66-
showMore={showMoreConfig !== null}
6764
templateProps={renderState.templateProps}
6865
toggleRefinement={refine}
6966
searchFacetValues={searchForFacetValues ? searchForItems : undefined}
7067
searchPlaceholder={searchForFacetValues.placeholder || 'Search for other...'}
7168
isFromSearch={isFromSearch}
69+
showMore={showMoreConfig !== null}
70+
toggleShowMore={toggleShowMore}
71+
isShowingMore={isShowingMore}
7272
/>,
7373
containerNode
7474
);
@@ -223,7 +223,7 @@ export default function refinementList({
223223
throw new Error('showMore.limit configuration should be > than the limit in the main configuration'); // eslint-disable-line
224224
}
225225

226-
const limitMax = showMoreConfig && showMoreConfig.limit || limit;
226+
const showMoreLimit = showMoreConfig && showMoreConfig.limit || limit;
227227
const containerNode = getContainerNode(container);
228228
const showMoreTemplates = showMoreConfig ? prefixKeys('show-more-', showMoreConfig.templates) : {};
229229
const searchForValuesTemplates = searchForFacetValues ? searchForFacetValues.templates : {};
@@ -249,8 +249,6 @@ export default function refinementList({
249249
templates: allTemplates,
250250
renderState: {},
251251
collapsible,
252-
limitMax,
253-
limit,
254252
autoHideContainer,
255253
showMoreConfig,
256254
searchForFacetValues,
@@ -261,7 +259,8 @@ export default function refinementList({
261259
return makeWidget({
262260
attributeName,
263261
operator,
264-
limit: limitMax,
262+
limit,
263+
showMoreLimit,
265264
sortBy,
266265
});
267266
} catch (e) {

0 commit comments

Comments
 (0)