Skip to content

Commit

Permalink
fix: ensure values not in options clear
Browse files Browse the repository at this point in the history
Closes #817
  • Loading branch information
Skaiir committed Nov 23, 2023
1 parent c4b98f3 commit e00d49d
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useContext, useEffect, useRef } from 'preact/hooks';
import { useContext, useRef } from 'preact/hooks';
import useOptionsAsync, { LOAD_STATES } from '../../hooks/useOptionsAsync';
import useRestrictedMultiSelectValues from '../../hooks/useRestrictedMultiSelectValues';
import classNames from 'classnames';
import { FormContext } from '../../context';

Expand Down Expand Up @@ -80,6 +81,14 @@ export default function Checklist(props) {
options
} = useOptionsAsync(field);

useRestrictedMultiSelectValues({
field,
loadState,
options,
values,
onChange: props.onChange
});

const { formId } = useContext(FormContext);
const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useContext, useRef } from 'preact/hooks';
import useOptionsAsync, { LOAD_STATES } from '../../hooks/useOptionsAsync';
import useRestrictedSingleSelectValue from '../../hooks/useRestrictedSingleSelectValue';
import classNames from 'classnames';
import { FormContext } from '../../context';

Expand Down Expand Up @@ -69,6 +70,14 @@ export default function Radio(props) {
options
} = useOptionsAsync(field);

useRestrictedSingleSelectValue({
field,
loadState,
options,
value,
onChange: props.onChange
});

const { formId } = useContext(FormContext);
const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useContext, useMemo, useRef, useState } from 'preact/hooks';

import useOptionsAsync, { LOAD_STATES } from '../../hooks/useOptionsAsync';
import { useService } from '../../hooks';
import useOptionsAsync, { LOAD_STATES } from '../../hooks/useOptionsAsync';
import useRestrictedMultiSelectValues from '../../hooks/useRestrictedMultiSelectValues';

import { FormContext } from '../../context';
import classNames from 'classnames';
Expand Down Expand Up @@ -59,6 +60,14 @@ export default function Taglist(props) {
options
} = useOptionsAsync(field);

useRestrictedMultiSelectValues({
field,
loadState,
options,
values,
onChange: props.onChange
});

// We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
const valueToOptionMap = useMemo(() => Object.assign({}, ...options.map((o, x) => ({ [o.value]: options[x] }))), [ options ]);

Expand Down Expand Up @@ -189,7 +198,7 @@ export default function Taglist(props) {
return (
<div class={ classNames('fjs-taglist-tag', { 'fjs-disabled': disabled, 'fjs-readonly': readonly }) } onMouseDown={ (e) => e.preventDefault() }>
<span class="fjs-taglist-tag-label">
{valueToOptionMap[v] ? valueToOptionMap[v].label : `unexpected value{${v}}`}
{ valueToOptionMap[v].label }
</span>
{ (!disabled && !readonly) && <button
type="button"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'preact/hooks';
import useOptionsAsync, { LOAD_STATES } from '../../../hooks/useOptionsAsync';
import { useService } from '../../../hooks';
import useRestrictedSingleSelectValue from '../../../hooks/useRestrictedSingleSelectValue';

import { FormContext } from '../../../context';

Expand Down Expand Up @@ -41,6 +42,14 @@ export default function SearchableSelect(props) {
options
} = useOptionsAsync(field);

useRestrictedSingleSelectValue({
field,
loadState,
options,
value,
onChange: props.onChange
});

// We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
const valueToOptionMap = useMemo(() => Object.assign({}, ...options.map((o, x) => ({ [o.value]: options[x] }))), [ options ]);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useContext, useMemo, useRef, useState } from 'preact/hooks';
import useOptionsAsync, { LOAD_STATES } from '../../../hooks/useOptionsAsync';
import useRestrictedSingleSelectValue from '../../../hooks/useRestrictedSingleSelectValue';

import { FormContext } from '../../../context';

Expand Down Expand Up @@ -38,6 +39,14 @@ export default function SimpleSelect(props) {
options
} = useOptionsAsync(field);

useRestrictedSingleSelectValue({
field,
loadState,
options,
value,
onChange: props.onChange
});

// We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
const valueToOptionMap = useMemo(() => Object.assign({}, ...options.map((o, x) => ({ [o.value]: options[x] }))), [ options ]);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useEffect } from 'preact/hooks';
import { LOAD_STATES } from './useOptionsAsync';

export default function(props) {

const {
field,
options,
loadState,
onChange,
values
} = props;

// Ensures that the values are always a subset of the options
useEffect(() => {

if (loadState !== LOAD_STATES.LOADED) {
return;
}

const hasValuesNotInOptions = values.some(v => !options.map(o => o.value).includes(v));

if (hasValuesNotInOptions) {
onChange({
field,
value: values.filter(v => options.map(o => o.value).includes(v))
});
}

}, [ field, options, onChange, JSON.stringify(values), loadState ]);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect } from 'preact/hooks';
import { LOAD_STATES } from './useOptionsAsync';

export default function(props) {

const {
field,
options,
loadState,
onChange,
value
} = props;

useEffect(() => {

if (loadState !== LOAD_STATES.LOADED) {
return;
}

const hasValueNotInOptions = value && !options.map(o => o.value).includes(value);

if (hasValueNotInOptions) {
onChange({
field,
value: null
});
}

}, [ field, options, onChange, value, loadState ]);

}

0 comments on commit e00d49d

Please sign in to comment.