I have encountered the following problem while binding a Multi-Select Combo Box:
- The value is a
string[], but the items are objects, like{ value: 'A', label: '1A' }. - The bean’s attribute requires a list of string UUIDs, not objects, so I need to set only the values/UUIDs as items, like
['A']. - I need to display the label because a UUID is not readable.
- When using the
multiSelectComboBoxRenderer, the overlay list displays nicely, but the chip still shows the UUID instead of a user-friendly label. item-label-pathdoes not work because the items are not objects.
While investigating the component sources, I found that I can override the _getItemLabel method of MultiSelectComboBoxMixin.
To integrate with the existing structure, I wrote a Lit directive for setting a custom item label generator:
export type ItemLabelGenerator = (item: any) => string
export class MultiSelectComboxBoxLabelGeneratorDirective extends Directive {
render(_callback: ItemLabelGenerator) { }
update(part: ElementPart, [callback]: [ItemLabelGenerator]) {
if (part.type !== PartType.ELEMENT) {
throw new Error('MultiSelectComboxBoxLabelGeneratorDirective can only be used on elements');
}
const el = part.element as HTMLElement;
if (el.tagName.toLowerCase() !== 'vaadin-multi-select-combo-box') {
throw new Error('MultiSelectComboxBoxLabelGeneratorDirective can only be used on vaadin-multi-select-combo-box');
}
(el as any)._getItemLabel = callback;
}
}
export const multiSelectComboBoxLabelGenerator = directive(MultiSelectComboxBoxLabelGeneratorDirective);
You can use the directive like this (Tested with Vaadin 24.6.12):
@customElement("test-view")
export class TestView extends View {
@state()
items: any[] = [{ value: 'A', label: "1A" }, { value: 'B', label: "2B" }, { value: 'C', label: "3C" }];
@state()
selectedItems: String[] = ["B"];
labelGenerator: ItemLabelGenerator = (item: any) => this.items.find(i => i.value === item).label
render() {
return html`
<vaadin-multi-select-combo-box
.selectedItems=${this.selectedItems}
.items=${this.items.map(i => i.value)}
@selected-items-changed=${(e: CustomEvent) => this.onSelectedItemsChanged(e.detail.value)}
${multiSelectComboBoxLabelGenerator(this.labelGenerator)}
${multiSelectComboBoxRenderer(item => html`${this.labelGenerator(item)}`, [this.items])}
>
</vaadin-multi-select-combo-box>
<p>${JSON.stringify(this.selectedItems)}</p>
`
}
onSelectedItemsChanged(value: any) {
this.selectedItems = value
}
}