Issue
Updated code to show the complete script logic.
I am trying to limit the number of selections based on a number I get from the database, but for this example I have hardcoded it to 3. The error I am receiving is "Cannot read properties of undefined (selectedHeadcount)". The code works when I comment out getOptionLabel and disableCloseOnSelect.
const rows = [
{ processPath: 'role1', headcount: 2 },
{ processPath: 'role2', headcount: 3 },
{ processPath: 'role3', headcount: 2 },
{ processPath: 'role4', headcount: 2 },
{ processPath: 'role5', headcount: 1 },
];
type EmployeesDictionary = Record<string, Record<string, string[] | number>>;
export const CriticalRolesContent: FunctionComponent = () => {
const employeesList = ['john', 'sally', 'mark', 'kevin']
console.log(employeesList, disableOptimizerButton);
const newDictionary: EmployeesDictionary = {};
rows.forEach((row) => {
newDictionary[row.processPath] = {
associates: [],
selectedHeadcount: 0,
};
});
console.log(newDictionary);
const [associateList, setAssociateList] = useState<EmployeesDictionary>(newDictionary);
const handleSelection = (processPath: string, associates: string[], reason: string, detail: any): void => {
setAssociateList((prevAssociateList) => ({
...prevAssociateList,
[processPath]: { associates: associates, selectedHeadcount: associates.length },
}));
};
console.log(associateList);
return (
<>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>Process Path</TableCell>
<TableCell>Associate Login</TableCell>
<TableCell>Headcount Allowed</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, rowIndex) => (
<TableRow
key={rowIndex}
sx={{
'&:last-child td, &:last-child th': { border: 0 },
}}>
<TableCell style={{ width: '35%' }}>{row.processPath}</TableCell>
<TableCell style={{ width: '45%' }} component='th' scope='row'>
<Autocomplete
multiple
id='employee-list'
options={employeesList}
limitTags={3}
// getOptionLabel={(option) => option}
// getOptionDisabled={(option) => associateList.processPath.selectedHeadcount >= 3}
// disableCloseOnSelect={associateList.processPath.selectedHeadcount >= 3}
renderInput={(params) => <TextField {...params} variant='standard' label='Select Employees' />}
onChange={(event, list, reason, detail) => handleSelection(row.processPath, list, reason, detail)}
/>
</TableCell>
<TableCell>{row.headcount}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
);
};
Solution
The associateList
value is something like this.
{
"role1": {
"associates": [],
"selectedHeadcount": 0
},
"role2": {
"associates": [],
"selectedHeadcount": 0
},
"role3": {
"associates": [],
"selectedHeadcount": 0
},
"role4": {
"associates": [],
"selectedHeadcount": 0
},
"role5": {
"associates": [],
"selectedHeadcount": 0
}
}
Its an object with keys of rows.processPath
. Thats the reason associateList.processPath.selectedHeadcount
is failing as there is no valued called processPath
in it.
Other issues are:
getOptionLabel={(option) => option} -> This should return string
options={row.name} -> This should be array
disableCloseOnSelect={associateList.processPath.selectedHeadcount >= 3} -> This should a boolean value
handleSelection(row.processPath, list, reason, detail) -> Cant find declaration for this
You will have to change associateList.processPath.selectedHeadcount
to associateList[row.processPath].selectedHeadcount
. As row.processPath
has the actual processPath that is available in the accociateList.
<Autocomplete
multiple
id="employee-list"
options={employeesList}
limitTags={3}
getOptionLabel={(option) => option}
getOptionDisabled={() =>
associateList[row.processPath].selectedHeadcount >= 3
}
disableCloseOnSelect={
associateList[row.processPath].selectedHeadcount >= 3
}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
label="Select Employees"
/>
)}
onChange={(event, list, reason, detail) =>
handleSelection(row.processPath, list, reason, detail)
}
/>
Edit: For the updated request you can declare a set to track which users are selected. Then based on user selection action you can keep updating it. Also you will have to update the handleSelection and getOptionDisabled prop.
// 1. Declare new state
const [selectedUsers, setSelectedUsers] = useState(new Set());
// 2. Updated handleSection
const handleSelection = (
processPath: string,
associates: string[],
reason: string,
detail: any
): void => {
if (reason === "selectOption") {
setSelectedUsers((prev) => {
const newSet = new Set(prev);
newSet.add(detail.option);
return newSet;
});
} else if (reason === "removeOption") {
setSelectedUsers((prev) => {
const newSet = new Set(prev);
newSet.delete(detail.option);
return newSet;
});
}
setAssociateList((prevAssociateList) => ({
...prevAssociateList,
[processPath]: {
associates: associates,
selectedHeadcount: associates.length,
},
}));
};
// 3. Updated getOptionDisabled
// The selected option will be available in same row
getOptionDisabled={(option) => {
const rule1 =
associateList[row.processPath].selectedHeadcount >= 3;
if (rule1) {
return true;
}
if (
associateList[row.processPath].associates?.includes(
option
)
) {
return false;
}
return selectedUsers.has(option);
}}
Answered By - Bhavesh Parvatkar
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.