Skip to content

Commit

Permalink
feat(application-system): Add clear on change (#17452)
Browse files Browse the repository at this point in the history
* Add shared clearing handler

* Add clearOnChange support to fieldbuilders and types

* Add clearOnChange support to controllers

* Add clearOnChange support to formfields

* Cleanup

* Add demonstration to example application

* Add extra info
  • Loading branch information
norda-gunni authored Jan 10, 2025
1 parent 1a3606f commit 1364f19
Show file tree
Hide file tree
Showing 27 changed files with 260 additions and 4 deletions.
2 changes: 2 additions & 0 deletions libs/application/core/src/lib/fieldBuilders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const extractCommonFields = (
nextButtonText,
marginBottom,
marginTop,
clearOnChange,
} = data

return {
Expand All @@ -91,6 +92,7 @@ const extractCommonFields = (
nextButtonText,
marginBottom,
marginTop,
clearOnChange,
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import {
buildAsyncSelectField,
buildCheckboxField,
buildDateField,
buildDescriptionField,
buildDividerField,
buildMultiField,
buildNationalIdWithNameField,
buildPhoneField,
buildRadioField,
buildSelectField,
buildSubSection,
buildTextField,
} from '@island.is/application/core'
import { FriggSchoolsByMunicipality } from '../../../utils/types'
import { friggSchoolsByMunicipalityQuery } from '../../../graphql/sampleQuery'

export const clearOnChangeSubsection = buildSubSection({
id: 'clearOnChangeSubsection',
title: 'Clear on change',
children: [
buildMultiField({
id: 'clearOnChangeMultiField',
title: 'Clear on change',
children: [
buildDescriptionField({
id: 'descriptionField',
title: '',
description: `Clear on change allows a field to clear other fields when its value or selection changes.
Below are some examples of fields that will clear the bottom field when changed.
Note that the fields that are cleared can be anywhere in the application, not just on the same screen.`,
}),
buildDescriptionField({
id: 'descriptionField2',
title: '',
description: `To try it out simply enter some text in the bottom text field
and change the selections in any of the other fields.`,
}),
buildAsyncSelectField({
id: 'asyncSelectField',
title: 'Async Select',
loadingError: 'Loading error',
clearOnChange: ['clearableTextField'],
loadOptions: async ({ apolloClient }) => {
const { data } =
await apolloClient.query<FriggSchoolsByMunicipality>({
query: friggSchoolsByMunicipalityQuery,
})

return (
data?.friggSchoolsByMunicipality?.map((municipality) => ({
value: municipality.name,
label: municipality.name,
})) ?? []
)
},
}),

buildSelectField({
id: 'selectField',
title: 'Select',
clearOnChange: ['clearableTextField'],
options: [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
],
}),

buildPhoneField({
id: 'phoneField',
title: 'Phone Field',
clearOnChange: ['clearableTextField'],
}),

buildDateField({
id: 'dateField',
title: 'Date Field',
clearOnChange: ['clearableTextField'],
}),

buildTextField({
id: 'textField',
title: 'Text Field',
clearOnChange: ['clearableTextField'],
}),

buildRadioField({
id: 'radioField',
title: 'Radio Field',
clearOnChange: ['clearableTextField'],
options: [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
],
}),

buildCheckboxField({
id: 'checkboxField',
title: 'Checkbox Field',
marginTop: 2,
clearOnChange: ['clearableTextField'],
options: [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
],
}),

buildNationalIdWithNameField({
id: 'nationalIdWithNameField',
title: 'NationalId With Name Field',
clearOnChange: ['clearableTextField'],
}),

buildDividerField({}),

buildTextField({
id: 'clearableTextField',
title: 'Clearable TextField',
placeholder: 'Text entered here will be cleared',
}),
],
}),
],
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { conditionsSubsection } from './conditionsSubsection'
import { conditions2Subsection } from './conditions2Subsection'
import { getDataFromExternalDataSubsection } from './getDataFromExternalDataSection'
import { validationSubsection } from './validadionSubsection'
import { clearOnChangeSubsection } from './clearOnChangeSubsection'

export const commonActionsSection = buildSection({
id: 'commonActions',
title: 'Common actions',
children: [
getDataFromExternalDataSubsection,
validationSubsection,
clearOnChangeSubsection,
conditionsSubsection,
conditions2Subsection,
],
Expand Down
1 change: 1 addition & 0 deletions libs/application/types/src/lib/Fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ export interface BaseField extends FormItem {
doesNotRequireAnswer?: boolean
marginBottom?: BoxProps['marginBottom']
marginTop?: BoxProps['marginTop']
clearOnChange?: string[]

// TODO use something like this for non-schema validation?
// validate?: (formValue: FormValue, context?: object) => boolean
Expand Down
1 change: 1 addition & 0 deletions libs/application/types/src/lib/Form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export interface FieldBaseProps<TAnswers = FormValue> {
field: Field
application: Application<TAnswers>
showFieldName?: boolean
clearOnChange?: string[]
goToScreen?: (id: string) => void
answerQuestions?: (answers: FormValue) => void
refetch?: () => void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ interface NationalIdWithNameProps {
showPhoneField?: boolean
showEmailField?: boolean
error?: string
clearOnChange?: string[]
}

export const NationalIdWithName: FC<
Expand Down Expand Up @@ -72,6 +73,7 @@ export const NationalIdWithName: FC<
showPhoneField = false,
showEmailField = false,
error,
clearOnChange,
}) => {
const fieldId = customId.length > 0 ? customId : id
const nameField = `${fieldId}.name`
Expand Down Expand Up @@ -233,6 +235,7 @@ export const NationalIdWithName: FC<
loading={searchPersons ? queryLoading : companyQueryLoading}
error={nationalIdFieldErrors}
disabled={disabled}
clearOnChange={clearOnChange}
/>
</GridColumn>
<GridColumn span={['1/1', '1/1', '1/1', '1/2']} paddingTop={2}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const AsyncSelectFormField: FC<React.PropsWithChildren<Props>> = ({
isSearchable,
isMulti,
required = false,
clearOnChange,
} = field
const { formatMessage, lang: locale } = useLocale()
const apolloClient = useApolloClient()
Expand Down Expand Up @@ -111,6 +112,7 @@ export const AsyncSelectFormField: FC<React.PropsWithChildren<Props>> = ({
backgroundColor={backgroundColor}
isSearchable={isSearchable}
isMulti={isMulti}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ interface Props extends FieldBaseProps {
}
export const BankAccountFormField = ({ field, application }: Props) => {
const { formatMessage, lang: locale } = useLocale()
const { marginBottom, marginTop, title, titleVariant, id } = field
const { marginBottom, marginTop, title, titleVariant, id, clearOnChange } =
field
const bankNumber = formatText(
coreDefaultFieldMessages.defaultBankAccountBankNumber,
application,
Expand Down Expand Up @@ -49,6 +50,7 @@ export const BankAccountFormField = ({ field, application }: Props) => {
format="####"
backgroundColor="blue"
autoFocus
clearOnChange={clearOnChange}
/>
</Box>
</GridColumn>
Expand All @@ -61,6 +63,7 @@ export const BankAccountFormField = ({ field, application }: Props) => {
placeholder="00"
format="##"
backgroundColor="blue"
clearOnChange={clearOnChange}
/>
</Box>
</GridColumn>
Expand All @@ -73,6 +76,7 @@ export const BankAccountFormField = ({ field, application }: Props) => {
placeholder="000000"
format="######"
backgroundColor="blue"
clearOnChange={clearOnChange}
/>
</Box>
</GridColumn>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const CheckboxFormField = ({
spacing,
marginTop,
marginBottom,
clearOnChange,
} = field
const { formatMessage, lang: locale } = useLocale()

Expand Down Expand Up @@ -107,6 +108,7 @@ export const CheckboxFormField = ({
}),
}),
)}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const DateFormField: FC<React.PropsWithChildren<Props>> = ({
readOnly,
marginTop,
marginBottom,
clearOnChange,
} = field
const { formatMessage, lang } = useLocale()

Expand Down Expand Up @@ -155,6 +156,7 @@ export const DateFormField: FC<React.PropsWithChildren<Props>> = ({
}
error={error}
onChange={onChange}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const DisplayFormField = ({ field, application }: Props) => {
suffix,
rightAlign = false,
halfWidthOwnline = false,
clearOnChange,
} = field
const { watch, setValue } = useFormContext()
const allValues = watch()
Expand Down Expand Up @@ -90,6 +91,7 @@ export const DisplayFormField = ({ field, application }: Props) => {
? undefined
: variant
}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export const FindVehicleFormField: FC<React.PropsWithChildren<Props>> = ({
energyFundsMessages,
marginTop,
marginBottom,
clearOnChange,
} = field

const [plate, setPlate] = useState<string>(
Expand Down Expand Up @@ -388,6 +389,7 @@ export const FindVehicleFormField: FC<React.PropsWithChildren<Props>> = ({
},
}}
maxLength={isMachine ? 7 : 5}
clearOnChange={clearOnChange}
/>
</Box>
<Button onClick={findVehicleByPlate} disabled={buttonDisabled}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const NationalIdWithNameFormField: FC<
phoneLabel={field.phoneLabel}
emailLabel={field.emailLabel}
error={error}
clearOnChange={field.clearOnChange}
/>
</Box>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const PhoneFormField: FC<React.PropsWithChildren<Props>> = ({
marginTop,
marginBottom,
onChange = () => undefined,
clearOnChange,
} = field
const { control, clearErrors } = useFormContext()
const { formatMessage, lang: locale } = useLocale()
Expand Down Expand Up @@ -94,6 +95,7 @@ export const PhoneFormField: FC<React.PropsWithChildren<Props>> = ({
defaultValue={getDefaultValue(field, application)}
backgroundColor={backgroundColor}
required={buildFieldRequired(application, required)}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const RadioFormField: FC<React.PropsWithChildren<Props>> = ({
widthWithIllustration,
marginTop,
marginBottom,
clearOnChange,
} = field
const { formatMessage, lang: locale } = useLocale()

Expand Down Expand Up @@ -118,6 +119,7 @@ export const RadioFormField: FC<React.PropsWithChildren<Props>> = ({
hasIllustration={hasIllustration}
paddingBottom={0}
paddingTop={2}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const SelectFormField: FC<React.PropsWithChildren<Props>> = ({
isMulti,
marginTop,
marginBottom,
clearOnChange,
} = field
const { formatMessage, lang: locale } = useLocale()

Expand Down Expand Up @@ -96,6 +97,7 @@ export const SelectFormField: FC<React.PropsWithChildren<Props>> = ({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore make web strict
onSelect={onSelect}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const TextFormField: FC<React.PropsWithChildren<Props>> = ({
marginBottom,
marginTop,
onChange = () => undefined,
clearOnChange,
} = field
const { clearErrors } = useFormContext()
const { formatMessage, lang: locale } = useLocale()
Expand Down Expand Up @@ -113,6 +114,7 @@ export const TextFormField: FC<React.PropsWithChildren<Props>> = ({
max={max}
min={min}
step={step}
clearOnChange={clearOnChange}
/>
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const VehicleRadioFormField: FC<React.PropsWithChildren<Props>> = ({
application,
field,
errors,
clearOnChange,
}) => {
const { formatMessage, formatDateFns } = useLocale()
const { setValue } = useFormContext()
Expand Down Expand Up @@ -269,6 +270,7 @@ export const VehicleRadioFormField: FC<React.PropsWithChildren<Props>> = ({
backgroundColor="blue"
onSelect={onRadioControllerSelect}
options={options}
clearOnChange={clearOnChange}
/>

{!selectedValue?.length && !!errors?.[field.id] && (
Expand Down
Loading

0 comments on commit 1364f19

Please sign in to comment.