Skip to content

Commit

Permalink
[useForm] - allow to replace getMetadata prop after the first render
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobz committed Dec 13, 2022
1 parent 1ecb017 commit a391f12
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 10 deletions.
10 changes: 8 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# 4.9.2 - 14.12.2022

**What’s Fixed**
* [useForm] - allow to replace getMetadata prop after the first render


# 4.9.1 - 01.12.2022

**What's New**
* [LockContext]: reworked lock context:
* [LockContext]: reworked lock context:
- make `tryRelease` method public
- `tryRelease` argument in `acquire` now optional, if isn't passed release lock immediately on request
- `withLock` now run passed action and get lock until action running
- `withLock` now run passed action and get lock until action running
* [useForm]: added close method, which try to leave form and ask to save unsaved changes
* [DatePickers]: added support for typing value according predefined set of formats

Expand Down
37 changes: 37 additions & 0 deletions uui-core/data/forms/__tests__/useForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,43 @@ describe('useForm', () => {
},
});
});

it('Should allow to replace getMetadata prop', async () => {
const props = {
value: { dummy: "test" },
onSave: (form) => Promise.resolve({form: form}),
onError: jest.fn(),
getMetadata: () => ({}),
validationOn: 'change',
}

const { result, rerender } = await mountHookWithContext<UseFormProps<IFoo>, IFormApi<IFoo>>(useForm<IFoo>, props);

act(() => result.current.lens.prop('dummy').set(""));

// The form is valid, as there's nothing in metadata
expect(result.current.isInvalid).toEqual(false);

// Update the getMetadata callback so 'dummy' is now required
act(() => {
rerender({
...props,
getMetadata: () => ({ props: { dummy: { isRequired: true }}}),
});
});

act(() => result.current.lens.prop('dummy').set(" "));

// We haven't change the form value, however with the new getMetadata is should be invalid
expect(result.current.isInvalid).toEqual(true);

expect(result.current.validationProps).toEqual({
dummy: {
isInvalid: true,
validationMessage: "The field is mandatory",
},
});
});
});

describe('isChanged, redo/undo/revert handing', () => {
Expand Down
21 changes: 13 additions & 8 deletions uui-core/data/forms/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export function useForm<T>(props: UseFormProps<T>): IFormApi<T> {
isInSaveMode: false,
});

const propsRef = useRef(props);
propsRef.current = props;

const getMetadata = (value: T) => propsRef.current.getMetadata ? propsRef.current.getMetadata(value) : {};

const prevFormValue = useRef<T>(props.value);

const formState = useRef(initialForm.current);
Expand Down Expand Up @@ -70,7 +75,7 @@ export function useForm<T>(props: UseFormProps<T>): IFormApi<T> {
const serverValidation = validateServerErrorState(form, lastSentForm, serverValidationState);
return mergeValidation(validationState, serverValidation);
},
getMetadata: () => props.getMetadata ? props.getMetadata(formState.current.form) : {},
getMetadata: () => getMetadata(formState.current.form),
}), []);

useEffect(() => {
Expand Down Expand Up @@ -158,7 +163,7 @@ export function useForm<T>(props: UseFormProps<T>): IFormApi<T> {

const updateValidationStates = (state: FormState<T>) => {
const valueToValidate = state.form;
const metadata = props.getMetadata ? props.getMetadata(valueToValidate) : {};
const metadata = getMetadata(valueToValidate);
const isInSaveMode = state.isInSaveMode;
const validationMode = isInSaveMode || !props.validationOn ? "save" : props.validationOn;
const validationState = uuiValidate(valueToValidate, metadata, initialForm.current.form, validationMode);
Expand All @@ -179,16 +184,16 @@ export function useForm<T>(props: UseFormProps<T>): IFormApi<T> {
newState = updateValidationStates(newState);
if (!newState.validationState.isInvalid) {
newState.isInProgress = true;
savePromise = props.onSave(formState.current.form)
savePromise = propsRef.current.onSave(formState.current.form)
.then((response) => handleSaveResponse(response, isSavedBeforeLeave))
.catch(err => props.onError?.(err));
.catch(err => propsRef.current.onError?.(err));
} else {
savePromise = Promise.reject();
}
return newState;
});
return savePromise;
}, [props.onSave]);
}, []);

const handleSaveResponse = (response: FormSaveResponse<T> | void, isSavedBeforeLeave?: boolean) => {
const newFormValue = response && response.form || formState.current.form;
Expand All @@ -211,8 +216,8 @@ export function useForm<T>(props: UseFormProps<T>): IFormApi<T> {
resetForm(newState);
removeUnsavedChanges();

if (props.onSuccess && response) {
props.onSuccess(response.form, isSavedBeforeLeave);
if (propsRef.current.onSuccess && response) {
propsRef.current.onSuccess(response.form, isSavedBeforeLeave);
}
};

Expand Down Expand Up @@ -254,7 +259,7 @@ export function useForm<T>(props: UseFormProps<T>): IFormApi<T> {

const validate = useCallback(() => {
updateFormState(currentState => updateValidationStates(currentState));
}, [props.getMetadata]);
}, []);

const handleRevert = useCallback(() => {
resetForm(initialForm.current);
Expand Down

0 comments on commit a391f12

Please sign in to comment.