I’m encountering an error with the MultiSelectComboBox component when used within an AutoCrud form. The error occurs specifically when selecting a row in the grid to edit a user. Interestingly, the same MultiSelectComboBox implementation works perfectly in a standalone AutoForm component.
The error message I am getting is:
Uncaught TypeError: this.selectedItems is undefined
__updateChips vaadin-multi-select-combo-box-mixin.js:822
_disabledChanged vaadin-multi-select-combo-box-mixin.js:484
I have tried with version 24.6.4 as well as 24.7.0.alpha6, same issue.
Here is the working implementation in my profile page with just an AutoForm:
import { ViewConfig } from '@vaadin/hilla-file-router/types.js';
import { RoleService, UserService } from "Frontend/generated/endpoints";
import UserModel from "Frontend/generated/ai/goacquire/shared/entity/UserModel";
import { AutoForm } from "@vaadin/hilla-react-crud";
import { useAuth } from "Frontend/auth";
import { useEffect, useState } from 'react';
import { useSignal } from "@vaadin/hilla-react-signals";
import User from 'Frontend/generated/ai/goacquire/shared/entity/User';
import Role from 'Frontend/generated/ai/goacquire/shared/entity/Role';
import { MultiSelectComboBox } from "@vaadin/react-components";
export const config: ViewConfig = {
menu: { exclude: true },
title: 'Profile',
loginRequired: true
};
export default function ProfileView() {
const { state } = useAuth();
const [user, setUser] = useState<User | null>(null);
// Add roles signal for the MultiSelectComboBox
const roles = useSignal<Role[]>([]);
useEffect(() => {
// Fetch roles when component mounts
RoleService.getRoles().then((value) => {
if (value) {
roles.value = value.filter((role): role is Role => role !== undefined);
}
});
// Fetch user data
if (state.user?.id) {
UserService.get(state.user.id)
.then((fetchedUser) => {
if (fetchedUser) {
setUser(fetchedUser);
}
});
}
}, [state.user?.id]);
return (
<AutoForm
service={UserService}
model={UserModel}
item={user}
visibleFields={['email', 'firstName', 'lastName', 'roles']}
fieldOptions={{
firstName: {
readonly: true
},
lastName: {
readonly: true
},
roles: {
renderer: ({ field }) => (
<MultiSelectComboBox
{...field}
items={roles.value}
itemIdPath="id"
itemValuePath="name"
itemLabelPath="name"
readonly={false}
/>
),
},
}}
/>
);
}
And here is the problematic version in my user admin page:
import { ViewConfig } from '@vaadin/hilla-file-router/types.js';
import { RoleService, UserService } from "Frontend/generated/endpoints";
import UserModel from "Frontend/generated/ai/goacquire/shared/entity/UserModel";
import { useEffect } from "react";
import { useSignal } from "@vaadin/hilla-react-signals";
import Role from "Frontend/generated/ai/goacquire/shared/entity/Role";
import User from "Frontend/generated/ai/goacquire/shared/entity/User";
import { AutoCrud } from "@vaadin/hilla-react-crud";
import { GridColumn, MultiSelectComboBox, TextField } from "@vaadin/react-components";
import Matcher from "Frontend/generated/com/vaadin/hilla/crud/filter/PropertyStringFilter/Matcher";
export const config: ViewConfig = {
menu: { order: 2, icon: 'vaadin:user' },
title: 'Users',
loginRequired: true,
};
export default function UsersView() {
// Initialize with an empty array and explicitly type it
const roles = useSignal<Role[]>([]);
useEffect(() => {
// Handle the Promise properly and ensure type safety
RoleService.getRoles().then((value) => {
// Ensure we only assign non-null values
if (value) {
// Filter out any undefined roles and assign
roles.value = value.filter((role): role is Role => role !== undefined);
}
});
}, []);
return (
<AutoCrud
service={UserService}
model={UserModel}
style={{ height: '100%' }}
gridProps={{
visibleColumns: ['email', 'firstName', 'lastName', 'roles', 'provider', 'active'],
customColumns: [
<GridColumn
key="roles"
header="Roles"
autoWidth
renderer={({ item }: { item: User }) => {
const { roles } = item;
return <span>{roles?.map((r) => r?.name).filter(Boolean).join(", ")}</span>;
}}
/>,
],
columnOptions: {
roles: {
headerFilterRenderer: ({ setFilter }) => (
<TextField
theme='small'
placeholder='Filter roles...'
onValueChanged={({ detail: { value } }) =>
setFilter({
propertyId: "roles.name",
filterValue: value,
matcher: Matcher.CONTAINS,
"@type": "propertyString",
})
}
/>
),
}
}
}}
formProps={{
visibleFields: ['email', 'firstName', 'lastName', 'roles', 'active'],
fieldOptions: {
firstName: {
readonly: true
},
lastName: {
readonly: true
},
roles: {
renderer: ({ field }) => (
<MultiSelectComboBox
{...field}
items={roles.value}
itemIdPath="id"
itemValuePath="name"
itemLabelPath="name"
/>
),
},
},
}}
/>
);
}
I’ve attached a short video showing the behavior.
Any help would be greatly appreciated.