-
Notifications
You must be signed in to change notification settings - Fork 555
Expand file tree
/
Copy pathconnectInfiniteHits.js
More file actions
151 lines (135 loc) · 4.7 KB
/
connectInfiniteHits.js
File metadata and controls
151 lines (135 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import escapeHTML, { TAG_PLACEHOLDER } from '../../lib/escape-highlight.js';
import { checkRendering } from '../../lib/utils.js';
const usage = `Usage:
var customInfiniteHits = connectInfiniteHits(function render(params, isFirstRendering) {
// params = {
// hits,
// results,
// showMore,
// isLastPage,
// instantSearchInstance,
// widgetParams,
// }
});
search.addWidget(
customInfiniteHits({
[ escapeHTML = true ],
[ transformItems ]
})
);
Full documentation available at https://community.algolia.com/instantsearch.js/v2/connectors/connectInfiniteHits.html
`;
/**
* @typedef {Object} InfiniteHitsRenderingOptions
* @property {Array<Object>} hits The aggregated matched hits from Algolia API of all pages.
* @property {Object} results The complete results response from Algolia API.
* @property {function} showMore Loads the next page of hits.
* @property {boolean} isLastPage Indicates if the last page of hits has been reached.
* @property {Object} widgetParams All original widget options forwarded to the `renderFn`.
*/
/**
* @typedef {Object} CustomInfiniteHitsWidgetOptions
* @property {boolean} [escapeHTML = true] Whether to escape HTML tags from `hits[i]._highlightResult`.
* @property {function(object[]):object[]} [transformItems] Function to transform the items passed to the templates.
*/
/**
* **InfiniteHits** connector provides the logic to create custom widgets that will render an continuous list of results retrieved from Algolia.
*
* This connector provides a `InfiniteHitsRenderingOptions.showMore()` function to load next page of matched results.
* @type {Connector}
* @param {function(InfiniteHitsRenderingOptions, boolean)} renderFn Rendering function for the custom **InfiniteHits** widget.
* @param {function} unmountFn Unmount function called when the widget is disposed.
* @return {function(CustomInfiniteHitsWidgetOptions)} Re-usable widget factory for a custom **InfiniteHits** widget.
* @example
* // custom `renderFn` to render the custom InfiniteHits widget
* function renderFn(InfiniteHitsRenderingOptions, isFirstRendering) {
* if (isFirstRendering) {
* InfiniteHitsRenderingOptions.widgetParams.containerNode
* .html('<div id="hits"></div><button id="show-more">Load more</button>');
*
* InfiniteHitsRenderingOptions.widgetParams.containerNode
* .find('#show-more')
* .on('click', function(event) {
* event.preventDefault();
* InfiniteHitsRenderingOptions.showMore();
* });
* }
*
* InfiniteHitsRenderingOptions.widgetParams.containerNode.find('#hits').html(
* InfiniteHitsRenderingOptions.hits.map(function(hit) {
* return '<div>' + hit._highlightResult.name.value + '</div>';
* })
* );
* };
*
* // connect `renderFn` to InfiniteHits logic
* var customInfiniteHits = instantsearch.connectors.connectInfiniteHits(renderFn);
*
* // mount widget on the page
* search.addWidget(
* customInfiniteHits({
* containerNode: $('#custom-infinite-hits-container'),
* })
* );
*/
export default function connectInfiniteHits(renderFn, unmountFn) {
checkRendering(renderFn, usage);
return (widgetParams = {}) => {
const { transformItems = items => items } = widgetParams;
let hitsCache = [];
let lastReceivedPage = -1;
const getShowMore = helper => () => helper.nextPage().search();
return {
getConfiguration() {
return widgetParams.escapeHTML ? TAG_PLACEHOLDER : undefined;
},
init({ instantSearchInstance, helper }) {
this.showMore = getShowMore(helper);
renderFn(
{
hits: hitsCache,
results: undefined,
showMore: this.showMore,
isLastPage: true,
instantSearchInstance,
widgetParams,
},
true
);
},
render({ results, state, instantSearchInstance }) {
if (state.page === 0) {
hitsCache = [];
lastReceivedPage = -1;
}
if (
widgetParams.escapeHTML &&
results.hits &&
results.hits.length > 0
) {
results.hits = escapeHTML(results.hits);
}
results.hits = transformItems(results.hits);
if (lastReceivedPage < state.page) {
hitsCache = [...hitsCache, ...results.hits];
lastReceivedPage = state.page;
}
const isLastPage = results.nbPages <= results.page + 1;
renderFn(
{
hits: hitsCache,
results,
showMore: this.showMore,
isLastPage,
instantSearchInstance,
widgetParams,
},
false
);
},
dispose() {
unmountFn();
},
};
};
}