From 7e6db65cace575823633ac3921442b058aa78a57 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 24 Sep 2023 23:36:34 +1000 Subject: [PATCH] Interactive forms (#5608) * Fix requery bug in related form field * Fixes for RelatedModelField - Better handling of null values * StockItem form fix - Clear 'supplier_part' field when 'part' field value changes * Add adjustFilters callback function - Allows query filters for a relatedfield to be changed on the fly --- .../components/forms/fields/ApiFormField.tsx | 6 +++- .../forms/fields/RelatedModelField.tsx | 28 +++++++++++++++---- .../src/functions/forms/StockForms.tsx | 16 ++++++++++- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/frontend/src/components/forms/fields/ApiFormField.tsx b/src/frontend/src/components/forms/fields/ApiFormField.tsx index 6442fe2c9a..19a9655183 100644 --- a/src/frontend/src/components/forms/fields/ApiFormField.tsx +++ b/src/frontend/src/components/forms/fields/ApiFormField.tsx @@ -18,6 +18,8 @@ import { ApiFormProps } from '../ApiForm'; import { ChoiceField } from './ChoiceField'; import { RelatedModelField } from './RelatedModelField'; +export type ApiFormData = UseFormReturnType>; + /** * Callback function type when a form field value changes */ @@ -25,7 +27,7 @@ export type ApiFormChangeCallback = { name: string; value: any; field: ApiFormFieldType; - form: UseFormReturnType>; + form: ApiFormData; }; /* Definition of the ApiForm field component. @@ -51,6 +53,7 @@ export type ApiFormChangeCallback = { * @param preFieldContent : Content to render before the field * @param postFieldContent : Content to render after the field * @param onValueChange : Callback function to call when the field value changes + * @param adjustFilters : Callback function to adjust the filters for a related field before a query is made */ export type ApiFormFieldType = { label?: string; @@ -71,6 +74,7 @@ export type ApiFormFieldType = { preFieldContent?: JSX.Element | (() => JSX.Element); postFieldContent?: JSX.Element | (() => JSX.Element); onValueChange?: (change: ApiFormChangeCallback) => void; + adjustFilters?: (filters: any, form: ApiFormData) => any; }; /* diff --git a/src/frontend/src/components/forms/fields/RelatedModelField.tsx b/src/frontend/src/components/forms/fields/RelatedModelField.tsx index ef86dd3811..5341d43b09 100644 --- a/src/frontend/src/components/forms/fields/RelatedModelField.tsx +++ b/src/frontend/src/components/forms/fields/RelatedModelField.tsx @@ -55,9 +55,14 @@ export function RelatedModelField({ useEffect(() => { // If a value is provided, load the related object if (form.values) { - let formPk = form.values[fieldName]; + let formPk = form.values[fieldName] ?? null; - if (formPk && formPk != pk) { + // If the value is unchanged, do nothing + if (formPk == pk) { + return; + } + + if (formPk != null) { let url = (definition.api_url || '') + formPk + '/'; // TODO: Fix this!! @@ -78,9 +83,11 @@ export function RelatedModelField({ setPk(data.pk); } }); + } else { + setPk(null); } } - }, [form]); + }, [form.values[fieldName]]); const [offset, setOffset] = useState(0); @@ -105,8 +112,14 @@ export function RelatedModelField({ url = url.substring(4); } + let filters = definition.filters ?? {}; + + if (definition.adjustFilters) { + filters = definition.adjustFilters(filters, form); + } + let params = { - ...definition.filters, + ...filters, search: searchText, offset: offset, limit: limit @@ -173,7 +186,7 @@ export function RelatedModelField({