Skip to content

Commit

Permalink
fix(clear): clearing wasn't working with too+ same type facets select…
Browse files Browse the repository at this point in the history
…ed (#1820)

* fix(clear): clearing wasn't working with too+ same type facets selected

* docs(default refinements): rephrase a bit

cc @mthuret

* Update Default_refinements.md
  • Loading branch information
mthuret authored and vvo committed Jan 11, 2017
1 parent eb2dec6 commit a9a2364
Show file tree
Hide file tree
Showing 16 changed files with 110 additions and 26 deletions.
35 changes: 34 additions & 1 deletion docgen/src/guide/Default_refinements.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,39 @@ const App = () =>
</InstantSearch>;
```

## Hiding default refinements

In some situations not only you want default refinements but you also do not want the user to be able to unselect them.

To do this, you can use a [`<VirtualWidgets/>`](guide/Virtual_widgets.html). It allows you to pre refine any widget without
rendering anything.

By default the [`<CurrentRefinements/>`](widgets/CurrentRefinements.html) widget or the
[`connectCurrentRefinements`](connectors/connectCurrentRefinements.html) connector will display your default refinements. If you want to hide them, you need to filter the items with `transformItems`.

```jsx
import {InstantSearch, SearchBox, Menu} from 'react-instantsearch/dom';
import {connectMenu} from 'react-instantsearch/connectors';

const VirtualMenu = connectMenu(() => null);

const App = () =>
<InstantSearch
appId="..."
apiKey="..."
indexName="..."
>
<div>
<CurrentRefinements
transformItems={items => items.filter(item => item.currentRefinement !== 'Orange')}
/>
<SearchBox/>
<VirtualMenu attributeName="fruits" defaultRefinement={'Orange'} />
<Menu attributeName="origin" defaultRefinement={'Spain'} />
</div>
</InstantSearch>;
```

**Notes:**
* The [search state guide](guide/Search_state.html) details all widgets and connectors state values...
* Default refinements are handy when used as [Virtual widgets](guide/Virtual_widgets.html).
Expand All @@ -39,4 +72,4 @@ const App = () =>
<div class="guide-nav-right">
Next: <a href="guide/Search_for_facet_values.html">Search for facet values →</a>
</div>
</div>
</div>
11 changes: 8 additions & 3 deletions docgen/src/guide/Sorting_and_filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ A frequent question that comes up is "How do I sort or filter the items of my wi
For this, widgets and connectors that are handling items expose a `transformItems` prop. This prop is a function that has the `items` provided
prop as a parameter. It will expect in return the `items` prop back.

## Supported widgets and connectors

This props can be found on every widgets or connectors that handle a list of `items`:
* [`<CurrentRefinements/>`](widgets/CurrentRefinements.html) and [`connectCurrentRefinements`](connectors/connectCurrentRefinements.html)
* [`<CurrentRefinements/>`](widgets/CurrentRefinements.html), [`<ClearAll/>`](widgets/ClearAll.html) and [`connectCurrentRefinements`](connectors/connectCurrentRefinements.html)
* [`<HierarchicalMenu/>`](widgets/HierarchicalMenu.html) and [`connectHierarchicalMenu`](connectors/connectHierarchicalMenu.html)
* [`<Menu/>`](widgets/Menu.html) and [`connectMenu`](connectors/connectMenu.html)
* [`<RefinementList/>`](widgets/RefinementList.html) and [`connectRefinementList`](connectors/connectRefinementList.html)
* [`<SortBy/>`](widgets/SortBy.html) and [`connectSortBy`](connectors/connectSortBy.html)
* [`<HitsPerPage/>`](widgets/HitsPerPage.html) and [`connectHitsPerPage`](connectors/connectHitsPerPage.html)
* [`<MultiRange/>`](widgets/MultiRange.html) and [`connectMultiRange`](connectors/connectMultiRange.html)

## Example

The following example will show you how to change the default sort order of the [`<RefinementList/>`](widgets/RefinementList.html) widget.

```jsx
Expand All @@ -38,8 +42,9 @@ const App = () =>
</InstantSearch>;
```

**Notes:**
* The example shows how to sort items, but you can also filter them
## Common use cases
* Sorting items
* Filtering items

<div class="guide-nav">
<div class="guide-nav-left">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export default createConnector({
attributeName: rootAttribute,
value: nextState => ({
...nextState,
[namespace]: {[id]: ''},
[namespace]: {...nextState[namespace], [id]: ''},
}),
currentRefinement,
}],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,14 @@ describe('connectHierarchicalMenu', () => {
value: metadata.items[0].value,
}],
});
});

it('items value function should clear it from the search state', () => {
const metadata = getMetadata({attributes: ['one']}, {hierarchicalMenu: {one: 'one', two: 'two'}});

const searchState = metadata.items[0].value({hierarchicalMenu: {one: 'one', two: 'two'}});

const searchState = metadata.items[0].value({hierarchicalMenu: {ok: 'wat'}});
expect(searchState).toEqual({hierarchicalMenu: {ok: ''}});
expect(searchState).toEqual({hierarchicalMenu: {one: '', two: 'two'}});
});

it('should return the right searchState when clean up', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-instantsearch/src/connectors/connectMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export default createConnector({
attributeName: props.attributeName,
value: nextState => ({
...nextState,
[namespace]: {[id]: ''},
[namespace]: {...nextState[namespace], [id]: ''},
}),
currentRefinement,
}],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,14 @@ describe('connectMenu', () => {
value: metadata.items[0].value,
}],
});
});

it('items value function should clear it from the search state', () => {
const metadata = getMetadata({attributeName: 'one'}, {menu: {one: 'one', two: 'two'}});

const searchState = metadata.items[0].value({menu: {one: 'one', two: 'two'}});

const searchState = metadata.items[0].value({menu: {wot: 'wat'}});
expect(searchState).toEqual({menu: {wot: ''}});
expect(searchState).toEqual({menu: {one: '', two: 'two'}});
});

it('should return the right searchState when clean up', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export default createConnector({
currentRefinement: label,
value: nextState => ({
...nextState,
[namespace]: {[id]: ''},
[namespace]: {...nextState[namespace], [id]: ''},
}),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,24 @@ describe('connectMultiRange', () => {
currentRefinement: 'YAY',
}],
});
});

it('items value function should clear it from the search state', () => {
const metadata = getMetadata(
{
attributeName: 'one',
items: [{
label: 'YAY',
start: 100,
end: 200,
}],
},
{multiRange: {one: '100:200', two: '200:400'}}
);

const searchState = metadata.items[0].value({multiRange: {one: '100:200', two: '200:400'}});

const searchState = metadata.items[0].value({multiRange: {wot: '100:200'}});
expect(searchState).toEqual({multiRange: {wot: ''}});
expect(searchState).toEqual({multiRange: {one: '', two: '200:400'}});
});

it('should return the right searchState when clean up', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ export default createConnector({
},

getMetadata() {
const id = getId();
return {
id,
};
return {id: getId()};
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export default createConnector({
attributeName: props.attributeName,
value: nextState => ({
...nextState,
[namespace]: {[id]: {}},
[namespace]: {...nextState[namespace], [id]: {}},
}),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ describe('connectRange', () => {
});
});

it('items value function should clear it from the search state', () => {
const metadata = getMetadata({attributeName: 'one'}, {range: {one: {min: 5}, two: {max: 4}}});

const searchState = metadata.items[0].value({range: {one: {min: 5}, two: {max: 4}}});

expect(searchState).toEqual({range: {one: {}, two: {max: 4}}});
});

it('should return the right searchState when clean up', () => {
let searchState = cleanUp({attributeName: 'name'}, {
range: {name: 'searchState', name2: 'searchState'},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export default createConnector({
currentRefinement: getCurrentRefinement(props, searchState),
value: nextState => ({
...nextState,
[namespace]: {[id]: ''},
[namespace]: {...nextState[namespace], [id]: ''},
}),
items: getCurrentRefinement(props, searchState).map(item => ({
label: `${item}`,
Expand All @@ -196,7 +196,7 @@ export default createConnector({

return {
...nextState,
[namespace]: {[id]: nextSelectedItems.length > 0 ? nextSelectedItems : ''},
[namespace]: {...nextState[namespace], [id]: nextSelectedItems.length > 0 ? nextSelectedItems : ''},
};
},
})),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,21 @@ describe('connectRefinementList', () => {
},
],
});
});

it('items value function should clear it from the search state', () => {
const metadata = getMetadata(
{attributeName: 'one'},
{refinementList: {one: ['one1', 'one2'], two: ['two']}}
);

let searchState = metadata.items[0].items[0].value({refinementList: {one: ['one1', 'one2'], two: ['two']}});

expect(searchState).toEqual({refinementList: {one: ['one2'], two: ['two']}});

let searchState = metadata.items[0].items[0].value({refinementList: {wot: ['wat', 'wut']}});
expect(searchState).toEqual({refinementList: {wot: ['wut']}});
searchState = metadata.items[0].items[1].value(searchState);
expect(searchState).toEqual({refinementList: {wot: ''}});

expect(searchState).toEqual({refinementList: {one: '', two: ['two']}});
});

it('should return the right searchState when clean up', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default createConnector({
attributeName: props.attributeName,
value: nextState => ({
...nextState,
[namespace]: {[id]: false},
[namespace]: {...nextState[namespace], [id]: false},
}),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,14 @@ describe('connectToggle', () => {
],
id: 't',
});
});

it('items value function should clear it from the search state', () => {
const metadata = getMetadata({attributeName: 'one', label: 'yep'}, {toggle: {one: true, two: false}});

const searchState = metadata.items[0].value({toggle: {one: true, two: false}});

const searchState = metadata.items[0].value({toggle: {t: true}});
expect(searchState).toEqual({toggle: {t: false}});
expect(searchState).toEqual({toggle: {one: false, two: false}});
});

it('should return the right searchState when clean up', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/react-instantsearch/src/widgets/ClearAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ClearAllComponent from '../components/ClearAll.js';
* to the search.
* @name ClearAll
* @kind widget
* @propType {function} [transformItems] - If provided, this function can be used to modify the `items` provided prop of the wrapped component (ex: for filtering or sorting items). this function takes the `items` prop as a parameter and expects it back in return.
* @themeKey ais-ClearAll__root - the widget button
* @translationKey reset - the clear all button value
* @example
Expand Down

0 comments on commit a9a2364

Please sign in to comment.