From 24f71ccc1aa1de132137a94c0bc48954d91a9566 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Thu, 18 Feb 2021 18:38:56 +0100 Subject: [PATCH] Improuve multi select In multi select with acceptNewValues option alway keep the new value as the first item in the list to make it easier to add it --- .../components/ComboMultipleDropdownList.jsx | 102 ++++++++++-------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/app/javascript/components/ComboMultipleDropdownList.jsx b/app/javascript/components/ComboMultipleDropdownList.jsx index b25d3cfe8..169e8629f 100644 --- a/app/javascript/components/ComboMultipleDropdownList.jsx +++ b/app/javascript/components/ComboMultipleDropdownList.jsx @@ -31,23 +31,46 @@ function ComboMultipleDropdownList({ if (label == undefined) { label = 'Choisir une option'; } - if (Array.isArray(options[0]) == false) { - options = options.map((o) => [o, o]); + if (!Array.isArray(options[0])) { + options = options.filter((o) => o).map((o) => [o, o]); } const inputRef = useRef(); const [term, setTerm] = useState(''); const [selections, setSelections] = useState(selected); const [newValues, setNewValues] = useState([]); + + const optionValueByLabel = (label) => { + const maybeOption = newValues.includes(label) + ? [label, label] + : options.find(([optionLabel]) => optionLabel == label); + return maybeOption ? maybeOption[1] : undefined; + }; + const optionLabelByValue = (value) => { + const maybeOption = newValues.includes(value) + ? [value, value] + : options.find(([, optionValue]) => optionValue == value); + return maybeOption ? maybeOption[0] : undefined; + }; + + const extraOptions = useMemo( + () => + acceptNewValues && term && term.length > 2 && !optionLabelByValue(term) + ? [[term, term]] + : [], + [acceptNewValues, term, newValues.join(',')] + ); const results = useMemo( () => - (term - ? matchSorter( - options.filter((o) => !o[0].startsWith('--')), - term - ) - : options - ).filter((o) => o[0] && !selections.includes(o[1])), - [term, selections.join(',')] + [ + ...extraOptions, + ...(term + ? matchSorter( + options.filter(([label]) => !label.startsWith('--')), + term + ) + : options) + ].filter(([, value]) => !selections.includes(value)), + [term, selections.join(','), newValues.join(',')] ); const hiddenField = useMemo( () => document.querySelector(`input[data-uuid="${hiddenFieldId}"]`), @@ -60,22 +83,12 @@ function ComboMultipleDropdownList({ const onKeyDown = (event) => { if (event.key === 'Enter') { - if (term && options.map((o) => o[0]).includes(term)) { - event.preventDefault(); - return onSelect(term); - } if ( - acceptNewValues && term && - matchSorter( - options.map((o) => o[0]), - term - ).length == 0 // ignore when was pressed for selecting popover option + [...extraOptions, ...options].map(([label]) => label).includes(term) ) { event.preventDefault(); - setNewValues([...newValues, term]); - saveSelection([...selections, term]); - setTerm(''); + return onSelect(term); } } }; @@ -89,19 +102,23 @@ function ComboMultipleDropdownList({ }; const onSelect = (value) => { - let sel = options.find((o) => o[0] == value)[1]; - saveSelection([...selections, sel]); + const maybeValue = [...extraOptions, ...options].find( + ([val]) => val == value + ); + const selectedValue = maybeValue && maybeValue[1]; + if (value) { + setNewValues([...newValues, selectedValue]); + saveSelection([...selections, selectedValue]); + } setTerm(''); }; - const onRemove = (value) => { - saveSelection( - selections.filter((s) => - newValues.includes(value) - ? s != value - : s !== options.find((o) => o[0] == value)[1] - ) - ); + const onRemove = (label) => { + const optionValue = optionValueByLabel(label); + if (optionValue) { + saveSelection(selections.filter((value) => value != optionValue)); + setNewValues(newValues.filter((value) => value != optionValue)); + } inputRef.current.focus(); }; @@ -116,10 +133,7 @@ function ComboMultipleDropdownList({ {selections.map((selection) => ( newValue == selection) || - options.find((o) => o[1] == selection)[0] - } + value={optionLabelByValue(selection)} /> ))} @@ -136,21 +150,15 @@ function ComboMultipleDropdownList({ {results.length === 0 && (

Aucun résultat{' '} - +

)} - {results.map((value, index) => { - if (value[0].startsWith('--')) { - return ; + {results.map(([label], index) => { + if (label.startsWith('--')) { + return ; } - return ; + return ; })}