@@ -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);
2427Full 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 = ! ( / ^ ( a n d | o r ) $ / ) . 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 } ;
0 commit comments