Skip to content

Commit 43310ed

Browse files
authored
fix(instantsearch.js/facet-dropdown): use render instead of init (#436)
1 parent 335094c commit 43310ed

File tree

3 files changed

+75
-68
lines changed

3 files changed

+75
-68
lines changed

instantsearch.js/facet-dropdown/index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ <h1 class="header-title">
5050
<div id="pagination"></div>
5151
</div>
5252

53-
<script src="https://cdn.jsdelivr.net/algoliasearch/3.32.0/algoliasearchLite.min.js"></script>
54-
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.9.1"></script>
53+
<script src="https://cdn.jsdelivr.net/npm/algoliasearch@4/dist/algoliasearch-lite.umd.js"></script>
54+
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4"></script>
5555
<script src="./src/app.js"></script>
5656
</body>
5757
</html>

instantsearch.js/facet-dropdown/src/Dropdown.js

+71-62
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function createDropdown(
3535
const makeWidget = instantsearch.widgets.panel({
3636
cssClasses,
3737
templates: {
38-
header: (options) => {
38+
header: options => {
3939
const { widgetParams } = options;
4040

4141
let text;
@@ -51,7 +51,7 @@ export function createDropdown(
5151
: '';
5252
// Get the number of refinements if the widget has `items`
5353
const nbRefinements = (options.items || []).filter(
54-
(item) => item.isRefined
54+
item => item.isRefined
5555
).length;
5656
// Format the button text
5757
text =
@@ -63,7 +63,7 @@ export function createDropdown(
6363
classNames.push(buttonClassName);
6464
} else if (typeof buttonClassName === 'function') {
6565
classNames.push(buttonClassName(options));
66-
} else if ((options.items || []).find((item) => item.isRefined)) {
66+
} else if ((options.items || []).find(item => item.isRefined)) {
6767
classNames.push(cssClasses.buttonRefined);
6868
}
6969

@@ -77,73 +77,80 @@ export function createDropdown(
7777
},
7878
})(baseWidget);
7979

80-
return (widgetParams) => {
80+
return widgetParams => {
8181
const widget = makeWidget(widgetParams);
82-
let cleanUp;
8382
let state = {};
83+
let rootElem, headerElem, closeButtonElem;
84+
85+
const open = () => {
86+
addClassName(rootElem, CLASS_OPENED);
87+
// This 'click' event is still being propagated,
88+
// so we add this event listener in the next tick.
89+
// Otherwise, it will immediately close the panel again.
90+
setTimeout(() => {
91+
state.windowClickListener = event => {
92+
// Close if the outside is clicked
93+
if (!rootElem.contains(event.target)) {
94+
close();
95+
}
96+
};
97+
// Add an event listener when the panel is opened
98+
window.addEventListener('click', state.windowClickListener);
99+
}, 0);
100+
};
101+
const close = () => {
102+
removeClassName(rootElem, CLASS_OPENED);
103+
// Remove the event listener when the panel is closed
104+
window.removeEventListener('click', state.windowClickListener);
105+
delete state.windowClickListener;
106+
};
107+
const isOpened = () => hasClassName(rootElem, CLASS_OPENED);
108+
const toggle = () => {
109+
if (isOpened()) {
110+
close();
111+
} else {
112+
open();
113+
}
114+
};
115+
116+
// Add a click listener to the header (button)
117+
const buttonListener = event => {
118+
if (!event.target.matches('.' + CLASS_BUTTON)) {
119+
return;
120+
}
121+
toggle();
122+
};
123+
124+
// Setup a clean-up function, which will be called in `dispose`.
125+
const cleanUp = () => {
126+
headerElem.removeEventListener('click', buttonListener);
127+
if (state.windowClickListener) {
128+
window.removeEventListener('click', state.windowClickListener);
129+
}
130+
};
84131

85132
// Return a modified version of the widget
86133
return {
87134
...widget,
88135
$$widgetType: 'cmty.facetDropdown',
89-
init: (options) => {
90-
const rootElem = document
91-
.querySelector(widgetParams.container)
92-
.querySelector('.ais-Panel');
93-
const headerElem = rootElem.querySelector('.ais-Panel-header');
94-
const closeButtonElem = rootElem.querySelector(
95-
'.' + CLASS_CLOSE_BUTTON
96-
);
97-
98-
const open = () => {
99-
addClassName(rootElem, CLASS_OPENED);
100-
// This 'click' event is still being propagated,
101-
// so we add this event listener in the next tick.
102-
// Otherwise, it will immediately close the panel again.
103-
setTimeout(() => {
104-
state.windowClickListener = (event) => {
105-
// Close if the outside is clicked
106-
if (!rootElem.contains(event.target)) {
107-
close();
108-
}
109-
};
110-
// Add an event listener when the panel is opened
111-
window.addEventListener('click', state.windowClickListener);
112-
}, 0);
113-
};
114-
const close = () => {
115-
removeClassName(rootElem, CLASS_OPENED);
116-
// Remove the event listener when the panel is closed
117-
window.removeEventListener('click', state.windowClickListener);
118-
delete state.windowClickListener;
119-
};
120-
const isOpened = () => hasClassName(rootElem, CLASS_OPENED);
121-
const toggle = () => {
122-
if (isOpened()) {
123-
close();
124-
} else {
125-
open();
126-
}
127-
};
136+
render: options => {
137+
if (!rootElem) {
138+
rootElem = document
139+
.querySelector(widgetParams.container)
140+
.querySelector('.ais-Panel');
141+
}
128142

129-
// Add a click listener to the header (button)
130-
const buttonListener = (event) => {
131-
if (!event.target.matches('.' + CLASS_BUTTON)) {
132-
return;
133-
}
134-
toggle();
135-
};
136-
headerElem.addEventListener('click', buttonListener);
143+
if (!headerElem) {
144+
headerElem = rootElem.querySelector('.ais-Panel-header');
137145

138-
closeButtonElem.addEventListener('click', close);
146+
headerElem.addEventListener('click', buttonListener);
147+
}
139148

140-
// Setup a clean-up function, which will be called in `dispose`.
141-
cleanUp = () => {
142-
headerElem.removeEventListener('click', buttonListener);
143-
if (state.windowClickListener) {
144-
window.removeEventListener('click', state.windowClickListener);
145-
}
146-
};
149+
if (!closeButtonElem) {
150+
closeButtonElem = rootElem.querySelector('.' + CLASS_CLOSE_BUTTON);
151+
152+
closeButtonElem.addEventListener('click', close);
153+
}
147154

148155
// Whenever uiState changes, it closes the panel.
149156
options.instantSearchInstance.use(() => ({
@@ -160,12 +167,14 @@ export function createDropdown(
160167
}
161168
},
162169
}));
163-
return widget.init.call(widget, options);
170+
171+
return widget.render.call(widget, options);
164172
},
165-
dispose: (options) => {
173+
dispose: options => {
166174
if (typeof cleanUp === 'function') {
167175
cleanUp();
168176
}
177+
169178
return widget.dispose.call(widget, options);
170179
},
171180
};

instantsearch.js/facet-dropdown/src/app.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ const search = instantsearch({
1515
const MOBILE_WIDTH = 375;
1616

1717
const brandDropdown = createDropdown(instantsearch.widgets.refinementList, {
18-
// closeOnChange: true,
1918
closeOnChange: () => window.innerWidth >= MOBILE_WIDTH,
2019
cssClasses: { root: 'my-BrandDropdown' },
2120
});
2221

2322
const refinementListDropdown = createDropdown(
2423
instantsearch.widgets.refinementList,
2524
{
26-
// closeOnChange: true,
2725
closeOnChange: () => window.innerWidth >= MOBILE_WIDTH,
2826
}
2927
);
@@ -44,13 +42,13 @@ const priceDropdown = createDropdown(instantsearch.widgets.rangeSlider, {
4442
const priceMenuDropdown = createDropdown(instantsearch.widgets.numericMenu, {
4543
buttonText({ items }) {
4644
const refinedItem = (items || []).find(
47-
(item) => item.label !== 'All' && item.isRefined
45+
item => item.label !== 'All' && item.isRefined
4846
);
4947
return refinedItem ? `Price (${refinedItem.label})` : 'Price Menu';
5048
},
5149
buttonClassName({ items }) {
5250
const isRefined = (items || []).find(
53-
(item) => item.label !== 'All' && item.isRefined
51+
item => item.label !== 'All' && item.isRefined
5452
);
5553
return isRefined && 'ais-Dropdown-button--refined';
5654
},

0 commit comments

Comments
 (0)