Я использую автозаполнение MUI и Formik и хотел сгруппировать их по категориям. Если у него нет sub_accounts
, то у него не должно быть метки заголовка. Примерно так: https://mui.com/material-ui/react-autocomplete/#grouped
КОДЫ------> НАЖМИТЕ ЗДЕСЬ
Ожидаемый результат в пользовательском интерфейсе выглядит примерно так:
Мелкая наличность
Наличные в банке - Bank of America
Наличные
CIB - Банк Вьетнама
Petty Cash
, Cash In Bank - Bank of America
, Cash
и CIB - Bank of Vietnam
должны быть выровнены.
Cash In Bank - Bank of America
и CIB - Bank of Vietnam
нельзя щелкнуть/выбрать — можно выбрать только его sub_accounts
, а также Petty Cash
и Cash
.
КОД
export const CashAccountAutocomplete = ({
field,
form: { touched, errors, setFieldValue, values },
disabled,
...props
}) => {
const [inputValue, setInputValue] = useState("");
const handleChangeEvent = (_, newValue, reason) => {
if (reason === "clear") {
setFieldValue(field.name, { id: "", name: "" });
return;
}
setFieldValue(field.name, newValue);
};
const handleInputChange = (_, newInputValue) => {
setInputValue(newInputValue);
};
const extractSubAccounts = (accounts) => {
if (!Array.isArray(accounts)) {
console.error("Invalid accounts data. Expected an array.");
return [];
}
return accounts.flatMap(
({ id, name, sub_accounts }) =>
sub_accounts && sub_accounts.length > 0
? extractSubAccounts(sub_accounts) // Recursively extract sub-accounts
: [{ id, name }] // Include the account if it has no sub-accounts
);
};
const filteredData = extractSubAccounts(accounts);
return (
<Autocomplete
{...field}
disabled = {disabled}
getOptionLabel = {(option) =>
typeof option === "string" ? option : option?.name || ""
}
renderOption = {(props, option) => {
return (
<li {...props} key = {option.id}>
{option?.name}
</li>
);
}}
filterOptions = {(x) => x}
options = {filteredData || []}
autoComplete
includeInputInList
filterSelectedOptions
noOptionsText = {"No data"}
onChange = {handleChangeEvent}
inputValue = {inputValue}
onInputChange = {handleInputChange}
renderInput = {(params) => (
<TextField
{...params}
{...props}
error = {touched[field.name] && errors[field.name] ? true : false}
helperText = {
touched[field.name] &&
errors[field.name] &&
String(errors[field.name].id)
}
/>
)}
fullWidth
/>
);
};
Я реализовал решение здесь с помощью хуков.
Вам необходимо отсортировать значение свойства options
Autocomplete
после фильтрации.
Возможно, я неправильно понял вашу проблему. Насколько я понимаю, ваша проблема заключалась в If it has no sub_accounts, then it shouldn't have a header label
. Я сосредоточился на этой части. Я не знаком с formik
. Решает ли реализация вашу проблему?
Не совсем. Вы удалили другие вещи, которые мне были нужны в CodeSandbox. Эту проблему следует решить вместе с этим. Можешь форкнуть мои коды и ящик, так будет проще
Мелкая наличность, наличные в банке - Bank of America, Cash и CIB - Банк Вьетнама должны быть согласованы
Обновите вспомогательную функцию extractSubAccounts
, чтобы установить свойство isHeader
только для элементов, которые будут заголовками, а затем также установите свойство isSelectable
, если нет параметров подмассива.
const extractSubAccounts = (accounts) => {
if (!Array.isArray(accounts)) {
console.error("Invalid accounts data. Expected an array.");
return [];
}
return accounts.flatMap(({ name, sub_accounts, ...account }) => [
{
...account,
name,
isHeader: true,
isSelectable: !sub_accounts?.length,
},
...sub_accounts,
]);
};
Обновите обратный вызов renderOptions
, чтобы проверить свойства inHeader
и isSelectable
каждого элемента списка. Идея состоит в том, что элементы списка, которые являются заголовками, а также параметрами, должны быть доступны для выбора и получать классы "MuiAutocomplete-option"
CSS, а затем также условно отменить отступы, которые имеют параметры, чтобы заголовки оставаться выровненными.
renderOption = {(props, option) => {
return (
<li
key = {option.id}
{...(!option.isHeader || option.isSelectable ? props : {})}
style = {{
paddingLeft:
option.isHeader || option.isSelectable ? "1rem" : "2rem",
}}
>
{option.isHeader && !option.isSelectable
? <strong>{option.name}</strong>
: option.name}
</li>
);
}}
@Джозеф Ах, упс, его все еще можно было выбрать, потому что реквизиты с обработчиками были безоговорочно распространены на все заголовки. Обновленный ответ. Если вы хотите, чтобы заголовки имели небольшое отступы, вы можете установить это в реквизите style
или реализовать фактически стилизованные компоненты, чтобы переопределить и установить желаемые отступы.
@Джозеф Сколько отступов тебе нужно/нужно? Только заголовки или все должно быть одинаково?
@Joseph Похоже, что значение отступа слева по умолчанию составляло около 1rem или 16 пикселей. Вы можете сделать отступ для опций еще на 1рем. Если вы просто хотите, чтобы они все выстроились в ряд, просто используйте style = {{ paddingLeft: "1rem" }}
.
Где находится часть
formik
?