GlCollapsibleListbox: Add ability to emit the entire selected item rather than just the value property
Currently for the listbox, when using `v-model` or a `select` listener, the emitted event only emits the item's `value` property. However, in many cases we need to get the item object itself rather than its value property. This is causing us to add a lot of boilerplate code where despite passing in the item objects to listbox:
```js
const items = [
{ value: 1, text: 'Item 1', fullPath: 'item/1' },
{ value: 2, text: 'Item 2', fullPath: 'item/2' },
{ value: 3, text: 'Item 3', fullPath: 'item/3' },
]
```
```vue
<gl-collapsible-listbox
:items="items"
@select="selectItem"
/>
```
in the select listener callback we need to do a `find()` to get back the selected item object:
```js
selectItem(value) {
this.selectedItem = this.items.find(({ id }) => id === value)
}
```
Examples of boilerplate code usage:
- [`projects_dropdown_filter.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue#L162-162)
- [`iteration_dropdown.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/ee/app/assets/javascripts/sidebar/components/iteration/iteration_dropdown.vue#L101-101)
- [`protected_branches_selector.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/ee/app/assets/javascripts/vue_shared/components/branches_selector/protected_branches_selector.vue#L191-191)
- [`topic_select.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/admin/topics/components/topic_select.vue#L78-78)
- [`board_add_new_column.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/boards/components/board_add_new_column.vue#L190-190)
- [`projects_dropdown.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/integrations/gitlab_slack_application/components/projects_dropdown.vue#L58-58)
- [`group_select.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/invite_members/components/group_select.vue#L94-94)
- [`type_select.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/issues/new/components/type_select.vue#L86-86)
- [`project_dropdown.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue#L75-75)
- [`type_select.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/issues/new/components/type_select.vue#L86-86)
- [`role_dropdown.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/1d11814eee74dd61af3c0d805c91804413bc442d/app/assets/javascripts/members/components/table/role_dropdown.vue#L59-59)
### Proposal
In addition to the item's value, also emit the item itself. It can be added as a second parameter to preserve backwards compatibility with existing code. Patch:
```patch
Index: src/components/base/new_dropdowns/listbox/listbox.vue
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/components/base/new_dropdowns/listbox/listbox.vue b/src/components/base/new_dropdowns/listbox/listbox.vue
--- a/src/components/base/new_dropdowns/listbox/listbox.vue (revision 5c2c59687b68f66906a9b246b3e7cddee5f67e01)
+++ b/src/components/base/new_dropdowns/listbox/listbox.vue (date 1701510050790)
@@ -627,9 +627,9 @@
},
onSelect(item, isSelected) {
if (this.multiple) {
- this.onMultiSelect(item.value, isSelected);
+ this.onMultiSelect(item, isSelected);
} else {
- this.onSingleSelect(item.value, isSelected);
+ this.onSingleSelect(item, isSelected);
}
},
isSelected(item) {
@@ -638,25 +638,28 @@
isFocused(item) {
return this.nextFocusedItemIndex === this.flattenedOptions.indexOf(item);
},
- onSingleSelect(value, isSelected) {
+ onSingleSelect(item, isSelected) {
if (isSelected) {
/**
* Emitted when selection is changed
*
* @event select
*/
- this.$emit('select', value);
+ this.$emit('select', item.value, item);
}
this.closeAndFocus();
},
- onMultiSelect(value, isSelected) {
+ onMultiSelect(item, isSelected) {
+ const selectedItems = this.items.filter(({ value }) => this.selectedValues.includes(value));
+
if (isSelected) {
- this.$emit('select', [...this.selectedValues, value]);
+ this.$emit('select', [...this.selectedValues, item.value], [...selectedItems, item]);
} else {
this.$emit(
'select',
- this.selectedValues.filter((selectedValue) => selectedValue !== value)
+ this.selectedValues.filter((selectedValue) => selectedValue !== item.value),
+ selectedItems.filter(({ value }) => value !== item.value)
);
}
},
```
issue