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