Skip to content

Commit 81fd9f8

Browse files
Merge pull request #78 from abhimediratta/feature/group-options
Feature/group options
2 parents 5b51217 + 9d7dd29 commit 81fd9f8

File tree

10 files changed

+76
-9
lines changed

10 files changed

+76
-9
lines changed

dev/Dev.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
:reduce-value-property="option => option.id"
77
ref="multi"
88
highlight-diff
9-
hide-search-inputs
109
@diff-changed="handleChange" />
1110
</div>
1211
</template>
@@ -31,7 +30,7 @@ export default {
3130
return {
3231
value: [],
3332
stringOptions: ['Chicago', 'Wisconsin', 'Houston'],
34-
options: [{ name: 'Chicago', id: 'ch' }, { name: 'Wisconsin', id: 'wi' }, { name: 'Houston', id: 'ho' }],
33+
options: [{ name: 'Chicago', id: 'ch', group: 'United States' }, { name: 'Wisconsin', id: 'wi', group: 'United States' }, { name: 'Houston', id: 'ho', group: 'India' }],
3534
showSelectAll: true,
3635
showWidget: true,
3736
};

dist/vue-multi-select-listbox.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vue-multi-select-listbox.css.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vue-multi-select-listbox.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vue-multi-select-listbox.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-multiselect-listbox",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "Multi-select widget where users can select options from a list in the left side to a list on the right",
55
"main": "dist/vue-multi-select-listbox.js",
66
"scripts": {
@@ -38,6 +38,7 @@
3838
"eslint-plugin-import": "^2.23.4",
3939
"eslint-plugin-vue": "^6.2.2",
4040
"html-webpack-plugin": "^3.2.0",
41+
"lodash.isfunction": "^3.0.9",
4142
"mini-css-extract-plugin": "^0.9.0",
4243
"node-sass": "^4.14.1",
4344
"postcss-loader": "^3.0.0",

src/components/MultiSelect/MultiSelect.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
:hide-search-input="hideSearchInputs"
1818
@onClickOption="onOptionSelect"
1919
:disabled="disabled"
20+
:groupProperty="reduceGroupProperty"
2021
/>
2122

2223
<div class="msl-multi-select__actions" v-if="!readOnly">
@@ -55,6 +56,7 @@
5556
@onClickOption="onOptionRemove"
5657
:disabled="disabled"
5758
:read-only="readOnly"
59+
:groupProperty="reduceGroupProperty"
5860
/>
5961
</div>
6062
</template>
@@ -165,6 +167,10 @@ export default {
165167
type: Function,
166168
default: (value) => value,
167169
},
170+
reduceGroupProperty: {
171+
type: Function,
172+
default: null
173+
},
168174
noOptionsText: {
169175
type: String,
170176
default: '',

src/components/SearchableList/SearchableList.vue

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
:placeholder="placeholderText"
99
>
1010
<div class="msl-searchable-list__items"
11-
:class="{ 'msl-searchable-list__items--disabled': disabled || readOnly }">
11+
:class="{ 'msl-searchable-list__items--disabled': disabled || readOnly }">
1212
<div
13+
v-if="!groupProperty"
1314
v-for="(option, index) in filteredListItems"
1415
:key="index"
1516
class="msl-searchable-list__item"
@@ -19,6 +20,23 @@
1920
{{ getOptionDisplay(option) }}
2021
</div>
2122

23+
<div
24+
v-if="groupProperty"
25+
v-for="groupKey in sortedGroupKeys"
26+
:key="groupKey"
27+
>
28+
<div class="msl-searchable-list__group">{{ groupKey }}</div>
29+
30+
<div
31+
v-for="option in groupedItems[groupKey].options"
32+
:key="option"
33+
class="msl-searchable-list__item msl-searchable-list__item--grouped"
34+
:class="{'msl-searchable-list__item--disabled': option.disabled || disabled || readOnly, [highlightClass]: highlightDiff && highlightedItemsMap[getValue(option)] }"
35+
@click="clickOption(option)">
36+
{{ getOptionDisplay(option) }}
37+
</div>
38+
</div>
39+
2240
<div
2341
v-if="noItems"
2442
class="msl-searchable-list__no-item"
@@ -39,6 +57,7 @@
3957
<script>
4058
import debounce from '../../utils/debounce';
4159
import isEmptyObject from '../../utils/isEmptyObject';
60+
import isFunction from 'lodash.isfunction';
4261
4362
function getValue(item, valueProperty) {
4463
return valueProperty(item);
@@ -86,6 +105,12 @@ export default {
86105
type: Function,
87106
default: (value) => value,
88107
},
108+
109+
groupProperty: {
110+
type: Function,
111+
default: null,
112+
},
113+
89114
noOptionsText: {
90115
type: String,
91116
default: 'No options',
@@ -171,6 +196,26 @@ export default {
171196
});
172197
},
173198
199+
groupedItems() {
200+
if (isFunction(this.groupProperty)) {
201+
const groupedItems = {}
202+
203+
this.filteredListItems.forEach(item => {
204+
const groupKey = this.groupProperty(item);
205+
groupedItems[groupKey] = groupedItems[groupKey] ?? { options: [] };
206+
groupedItems[groupKey].options.push(item)
207+
});
208+
209+
return groupedItems;
210+
}
211+
212+
return {};
213+
},
214+
215+
sortedGroupKeys() {
216+
return Object.keys(this.groupedItems).sort()
217+
},
218+
174219
filteredListItems() {
175220
if (this.searchText != null && this.searchText !== '') {
176221
return this.availableItems.filter(function filterItem(item) {

src/scss/modules/_searchable-list.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@
4949
}
5050
}
5151

52+
.msl-searchable-list__group {
53+
padding: 5px 10px;
54+
font-size: 1em;
55+
font-weight: bold;
56+
}
57+
58+
.msl-searchable-list__item--grouped {
59+
padding-left: 20px;
60+
}
61+
5262

5363
.msl-searchable-list__item--removed {
5464
background: red;

0 commit comments

Comments
 (0)