Skip to content

Added new prop: keepSelectionOrder #162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class Example extends Component {
| `responsiveHeight` | `string` | 400px | Responsive height of the wrapping component, can send percent for example: `70%` |
| `withGrouping` | `boolean` | false | Your items will be grouped by the group prop values - see "item grouping" section below |
| `showSelectedItemsSearch` | `boolean` | false | toggle to show search option in detination list. |
| `keepSelectionOrder` | `boolean` | false | keep selection order in the detination list |
| `searchSelectedItemsValue` | `string` | | The value of the search field for destination list. |
| `searchSelectedItemsChanged` | `function` | | Function to handle the change of search field for destination list. Accepts value as a single argument. |
| `selectedItemsFilterFunction` | `function` | based on label | Is the same as filterFunction by default to filter items based on the search query in destination list. |
Expand Down
8 changes: 6 additions & 2 deletions src/components/multi_select.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class MultiSelect extends PureComponent {
showSearch: PropTypes.bool,
showSelectAll: PropTypes.bool,
showSelectedItems: PropTypes.bool,
keepSelectionOrder: PropTypes.bool,
searchIcon: PropTypes.string,
deleteIcon: PropTypes.string,
searchRenderer: PropTypes.func,
Expand Down Expand Up @@ -55,7 +56,8 @@ export class MultiSelect extends PureComponent {
loaderRenderer: Loader,
withGrouping: false,
generateClassName: defaultGenerateClassName,
showSelectedItemsSearch: false
showSelectedItemsSearch: false,
keepSelectionOrder: false
};

calculateHeight() {
Expand Down Expand Up @@ -112,7 +114,8 @@ export class MultiSelect extends PureComponent {
searchSelectedItemsValue,
filterSelectedItems,
filteredSelectedItems,
isLocked
isLocked,
keepSelectionOrder
} = this.props;
const calculatedHeight = this.calculateHeight();
const selectedIds = selectedItems.map(item => item.id);
Expand Down Expand Up @@ -151,6 +154,7 @@ export class MultiSelect extends PureComponent {
withGrouping={withGrouping}
listRenderer={listRenderer}
isLocked={isLocked}
keepSelectionOrder={keepSelectionOrder}
/>
)}
{!loading && showSelectedItems && (
Expand Down
18 changes: 14 additions & 4 deletions src/components/multi_select_state.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const withMultiSelectState = WrappedComponent =>
}

selectItem(event, id) {
const { items } = this.props;
const { items, keepSelectionOrder } = this.props;
const { selectedItems, firstItemShiftSelected } = this.state;
if (!selectedItems.find(item => item.id === id)) {
if (event.shiftKey && firstItemShiftSelected !== undefined) {
Expand All @@ -125,15 +125,25 @@ const withMultiSelectState = WrappedComponent =>
const index = items.findIndex(item => item.id === id);
this.setState({ firstItemShiftSelected: index });
}
this.setNewItemsBySelectItem(id, items, selectedItems);
this.setNewItemsBySelectItem(
id,
items,
selectedItems,
keepSelectionOrder
);
}
} else {
this.unselectItems([id]);
}
}

setNewItemsBySelectItem(id, items, selectedItems) {
const newSelectedItems = getNewSelectedItems(id, items, selectedItems);
setNewItemsBySelectItem(id, items, selectedItems, keepSelectionOrder) {
const newSelectedItems = getNewSelectedItems(
id,
items,
selectedItems,
keepSelectionOrder
);
const newFilteredSelectedItems = this.getNewFilteredSelectedItems(
newSelectedItems
);
Expand Down
30 changes: 22 additions & 8 deletions src/components/multi_select_state_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,26 @@ export const getMinMaxIndexes = (currentIndex, firstItemShiftSelected) =>
export const isWithin = (index, { minIndex, maxIndex }) =>
index >= minIndex && index <= maxIndex;

export const getNewSelectedItems = (itemId, items, selectedItems) => {
const sourceItems = items.filter(
item => item.id === itemId || findItem(item, selectedItems)
);
const destinationItems = selectedItems.filter(
selectedItem => !findItem(selectedItem, items)
);
return [...destinationItems, ...sourceItems];
export const getNewSelectedItems = (
itemId,
items,
selectedItems,
keepSelectionOrder
) => {
let alreadySelectedItems = [];
let sourceItems = [];
let destinationItems = [];

if (keepSelectionOrder) {
// In order to keep selection order on the list,
// First, iterate threw already selectedItems
alreadySelectedItems = selectedItems.filter(item => findItem(item, items));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. alreadySelectedItems is the same that contains in selectedItems, I think doesn't make seanse to do such filtering
  2. your fix doesn't work when I use selection with Shift

sourceItems = items.filter(item => item.id === itemId);
} else {
sourceItems = items.filter(
item => item.id === itemId || findItem(item, selectedItems)
);
}

return [...alreadySelectedItems, ...sourceItems];
};
27 changes: 21 additions & 6 deletions stories/multi-select.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,21 @@ storiesOf("React Multi Select", module)
);
})
)
.add(
"with keep selection order",
withReadme(Readme, () => {
return (
<ReactMultiSelect
items={utils.items}
loading={boolean("Loading", false)}
onChange={action("onChange")}
showSearch={boolean("Show search", true)}
showSelectAll={boolean("Show select all", true)}
keepSelectionOrder={boolean("keep selection order", true)}
/>
);
})
)
.add(
"With some of the items disabled",
withReadme(Readme, () => {
Expand Down Expand Up @@ -363,15 +378,12 @@ storiesOf("React Multi Select", module)
withReadme(Readme, () => {
class SelectedItemsController extends React.Component {
SINGLE_ITEM = [{ id: 1, label: "Item 1" }];
MULTI_ITEMS = [
{ id: 2, label: "Item 2" },
{ id: 4, label: "Item 4" }
]
MULTI_ITEMS = [{ id: 2, label: "Item 2" }, { id: 4, label: "Item 4" }];

constructor(props) {
super(props);
this.state = {
selectedItems: this.SINGLE_ITEM,
selectedItems: this.SINGLE_ITEM
};
}

Expand All @@ -384,7 +396,10 @@ storiesOf("React Multi Select", module)
type="button"
onClick={() => {
this.setState({
selectedItems: this.state.selectedItems.length > 1 ? this.SINGLE_ITEM : this.MULTI_ITEMS
selectedItems:
this.state.selectedItems.length > 1
? this.SINGLE_ITEM
: this.MULTI_ITEMS
});
}}
/>
Expand Down
Loading