+
+
+The infinite hits widget is like the hits widget but instead of relying on an external pagination widget, it displays a button to load more results.
+It will display the results as one continuous long page. Its usage is particularly recommended in a mobile context. Even though it is not incompatible, it does not go well with the pagination widget.
+It accepts a [Mustache](https://mustache.github.io/) template string or a function returning a string. See the [templates](#templates) section.
+{:.description}
+
+
+For better control over what kind of data is returned, we suggest you configure the
+[attributeToRetrieve](https://www.algolia.com/doc/rest#param-attributesToRetrieve)
+and
+[attributeToHighlight](https://www.algolia.com/doc/rest#param-attributesToHighlight) of your index.
+
);
}
@@ -32,6 +38,7 @@ InfiniteHits.propTypes = {
showMore: React.PropTypes.function,
showMoreLabel: React.PropTypes.string,
templateProps: React.PropTypes.object.isRequired,
+ isLastPage: React.PropTypes.bool.isRequired,
};
export default InfiniteHits;
diff --git a/src/widgets/infinite-hits/__tests__/infinite-hits-test.js b/src/widgets/infinite-hits/__tests__/infinite-hits-test.js
index 5dafc27402..5d01dd17a9 100644
--- a/src/widgets/infinite-hits/__tests__/infinite-hits-test.js
+++ b/src/widgets/infinite-hits/__tests__/infinite-hits-test.js
@@ -67,6 +67,27 @@ describe('infiniteHits()', () => {
expect(ReactDOM.render.secondCall.args[1]).toEqual(container);
});
+ it('if it is the last page, then the props should contain isLastPage true', () => {
+ props = getProps();
+ const state = {page: 0};
+ widget.render({
+ results: {...results, page: 0, nbPages: 2},
+ state,
+ });
+ widget.render({
+ results: {...results, page: 1, nbPages: 2},
+ state,
+ });
+
+ expect(ReactDOM.render.calledTwice).toBe(true, 'ReactDOM.render called twice');
+ const propsWithIsLastPageFalse = {...(getProps({...results, page: 0, nbPages: 2})), isLastPage: false};
+ expect(ReactDOM.render.firstCall.args[0]).toEqualJSX();
+ expect(ReactDOM.render.firstCall.args[1]).toEqual(container);
+ const propsWithIsLastPageTrue = {...(getProps({...results, page: 1, nbPages: 2})), isLastPage: true};
+ expect(ReactDOM.render.secondCall.args[0]).toEqualJSX();
+ expect(ReactDOM.render.secondCall.args[1]).toEqual(container);
+ });
+
it('does not accept both item and allItems templates', () => {
expect(infiniteHits.bind({container, templates: {item: '', allItems: ''}})).toThrow();
});
@@ -85,10 +106,10 @@ describe('infiniteHits()', () => {
infiniteHits.__ResetDependency__('defaultTemplates');
});
- function getProps() {
+ function getProps(otherResults) {
return {
- hits: results.hits,
- results,
+ hits: (otherResults || results).hits,
+ results: otherResults || results,
templateProps,
cssClasses: {
root: 'ais-infinite-hits root cx',
@@ -98,6 +119,7 @@ describe('infiniteHits()', () => {
},
showMore: () => {},
showMoreLabel: 'Show more results',
+ isLastPage: false,
};
}
});
diff --git a/src/widgets/infinite-hits/infinite-hits.js b/src/widgets/infinite-hits/infinite-hits.js
index 22d6841a3a..a90d5ae600 100644
--- a/src/widgets/infinite-hits/infinite-hits.js
+++ b/src/widgets/infinite-hits/infinite-hits.js
@@ -13,19 +13,20 @@ const bem = bemHelper('ais-infinite-hits');
/**
* Display the list of results (hits) from the current search
- * @function hits
+ * @function infiniteHits
* @param {string|DOMElement} options.container CSS Selector or DOMElement to insert the widget
* @param {number} [options.hitsPerPage=20] The number of hits to display per page [*]
* @param {Object} [options.templates] Templates to use for the widget
- * @param {string|Function} [options.templates.empty=''] Template to use when there are no results.
- * @param {string|Function} [options.templates.item=''] Template to use for each result. This template will receive an object containing a single record.
+ * @param {string|Function} [options.templates.empty=""] Template to use when there are no results.
+ * @param {string|Function} [options.templates.item=""] Template to use for each result. This template will receive an object containing a single record.
+ * @param {string} [options.showMoreLabel="Show more results"] label used on the show more button
* @param {Object} [options.transformData] Method to change the object passed to the templates
* @param {Function} [options.transformData.empty] Method used to change the object passed to the `empty` template
* @param {Function} [options.transformData.item] Method used to change the object passed to the `item` template
* @param {Object} [options.cssClasses] CSS classes to add
* @param {string|string[]} [options.cssClasses.root] CSS class to add to the wrapping element
* @param {string|string[]} [options.cssClasses.empty] CSS class to add to the wrapping element when no results
- * @param {string|string[]} [options.7cssClasses.item] CSS class to add to each result
+ * @param {string|string[]} [options.cssClasses.item] CSS class to add to each result
* @return {Object}
*/
const usage = `
@@ -34,6 +35,7 @@ infiniteHits({
container,
[ cssClasses.{root,empty,item}={} ],
[ templates.{empty,item} | templates.{empty} ],
+ [ showMoreLabel="Show more results" ]
[ transformData.{empty,item} | transformData.{empty} ],
[ hitsPerPage=20 ]
})`;
@@ -80,6 +82,8 @@ function infiniteHits({
hitsCache = [...hitsCache, ...results.hits];
+ const isLastPage = results.nbPages <= results.page + 1;
+
ReactDOM.render(
,
containerNode