Skip to content

Commit 63840dc

Browse files
feat(numeric-selector): implement transformItems
1 parent b0f8611 commit 63840dc

File tree

4 files changed

+95
-6
lines changed

4 files changed

+95
-6
lines changed

dev/app/builtin/stories/numeric-selector.stories.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,29 @@ export default () => {
4545
);
4646
})
4747
);
48+
stories.add(
49+
'with transformed items',
50+
wrapWithHits(container => {
51+
window.search.addWidget(
52+
instantsearch.widgets.numericSelector({
53+
container,
54+
operator: '=',
55+
attributeName: 'rating',
56+
options: [
57+
{ label: 'No rating selected', value: undefined },
58+
{ label: 'Rating: 5', value: 5 },
59+
{ label: 'Rating: 4', value: 4 },
60+
{ label: 'Rating: 3', value: 3 },
61+
{ label: 'Rating: 2', value: 2 },
62+
{ label: 'Rating: 1', value: 1 },
63+
],
64+
transformItems: items =>
65+
items.map(item => ({
66+
...item,
67+
label: `${item.label} (transformed)`,
68+
})),
69+
})
70+
);
71+
})
72+
);
4873
};

src/connectors/numeric-selector/__tests__/connectNumericSelector-test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,55 @@ describe('connectNumericSelector', () => {
7474
});
7575
});
7676

77+
it('Renders during init and render with transformed items', () => {
78+
const rendering = jest.fn();
79+
const makeWidget = connectNumericSelector(rendering);
80+
const listOptions = [
81+
{ name: '10', value: 10 },
82+
{ name: '20', value: 20 },
83+
{ name: '30', value: 30 },
84+
];
85+
const widget = makeWidget({
86+
attributeName: 'numerics',
87+
options: listOptions,
88+
transformItems: items =>
89+
items.map(item => ({ ...item, label: 'transformed' })),
90+
});
91+
92+
const config = widget.getConfiguration({}, {});
93+
94+
const helper = jsHelper({}, '', config);
95+
helper.search = jest.fn();
96+
97+
widget.init({
98+
helper,
99+
state: helper.state,
100+
createURL: () => '#',
101+
onHistoryChange: () => {},
102+
});
103+
104+
const firstRenderingOptions = rendering.mock.calls[0][0];
105+
expect(firstRenderingOptions.options).toEqual([
106+
{ name: '10', value: 10, label: 'transformed' },
107+
{ name: '20', value: 20, label: 'transformed' },
108+
{ name: '30', value: 30, label: 'transformed' },
109+
]);
110+
111+
widget.render({
112+
results: new SearchResults(helper.state, [{ nbHits: 0 }]),
113+
state: helper.state,
114+
helper,
115+
createURL: () => '#',
116+
});
117+
118+
const secondRenderingOptions = rendering.mock.calls[1][0];
119+
expect(secondRenderingOptions.options).toEqual([
120+
{ name: '10', value: 10, label: 'transformed' },
121+
{ name: '20', value: 20, label: 'transformed' },
122+
{ name: '30', value: 30, label: 'transformed' },
123+
]);
124+
});
125+
77126
it('Reads the default value from the URL if possible', () => {
78127
// test that the dummyRendering is called with the isFirstRendering
79128
// flag set accordingly

src/connectors/numeric-selector/connectNumericSelector.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ search.addWidget(
1515
customNumericSelector({
1616
attributeName,
1717
options,
18-
[ operator = '=' ]
18+
[ operator = '=' ],
19+
[ transformItems ]
1920
})
2021
);
2122
Full documentation available at https://community.algolia.com/instantsearch.js/v2/connectors/connectNumericSelector.html
@@ -33,6 +34,7 @@ Full documentation available at https://community.algolia.com/instantsearch.js/v
3334
* @property {string} attributeName Name of the attribute for faceting (eg. "free_shipping").
3435
* @property {NumericSelectorOption[]} options Array of objects defining the different values and labels.
3536
* @property {string} [operator = '='] The operator to use to refine. Supports following operators: <, <=, =, >, >= and !=.
37+
* @property {function(object[]):object[]} [transformItems] Function to transform the items passed to the templates.
3638
*/
3739

3840
/**
@@ -98,7 +100,12 @@ export default function connectNumericSelector(renderFn, unmountFn) {
98100
checkRendering(renderFn, usage);
99101

100102
return (widgetParams = {}) => {
101-
const { attributeName, options, operator = '=' } = widgetParams;
103+
const {
104+
attributeName,
105+
options,
106+
operator = '=',
107+
transformItems = items => items,
108+
} = widgetParams;
102109

103110
if (!attributeName || !options) {
104111
throw new Error(usage);
@@ -131,7 +138,7 @@ export default function connectNumericSelector(renderFn, unmountFn) {
131138
renderFn(
132139
{
133140
currentRefinement: this._getRefinedValue(helper.state),
134-
options,
141+
options: transformItems(options),
135142
refine: this._refine,
136143
hasNoResults: true,
137144
instantSearchInstance,
@@ -145,7 +152,7 @@ export default function connectNumericSelector(renderFn, unmountFn) {
145152
renderFn(
146153
{
147154
currentRefinement: this._getRefinedValue(helper.state),
148-
options,
155+
options: transformItems(options),
149156
refine: this._refine,
150157
hasNoResults: results.nbHits === 0,
151158
instantSearchInstance,

src/widgets/numeric-selector/numeric-selector.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ const usage = `Usage: numericSelector({
3131
attributeName,
3232
options,
3333
cssClasses.{root,select,item},
34-
autoHideContainer
34+
autoHideContainer,
35+
transformItems
3536
})`;
3637

3738
/**
@@ -55,6 +56,7 @@ const usage = `Usage: numericSelector({
5556
* @property {NumericOption[]} options Array of objects defining the different values and labels.
5657
* @property {string} [operator='='] The operator to use to refine.
5758
* @property {boolean} [autoHideContainer=false] Hide the container when no results match.
59+
* @property {function(object[]):object[]} [transformItems] Function to transform the items passed to the templates.
5860
* @property {NumericSelectorCSSClasses} [cssClasses] CSS classes to be added.
5961
*/
6062

@@ -96,6 +98,7 @@ export default function numericSelector({
9698
options,
9799
cssClasses: userCssClasses = {},
98100
autoHideContainer = false,
101+
transformItems,
99102
}) {
100103
const containerNode = getContainerNode(container);
101104
if (!container || !options || options.length === 0 || !attributeName) {
@@ -121,7 +124,12 @@ export default function numericSelector({
121124
specializedRenderer,
122125
() => unmountComponentAtNode(containerNode)
123126
);
124-
return makeNumericSelector({ operator, attributeName, options });
127+
return makeNumericSelector({
128+
operator,
129+
attributeName,
130+
options,
131+
transformItems,
132+
});
125133
} catch (e) {
126134
throw new Error(usage);
127135
}

0 commit comments

Comments
 (0)