Skip to content

Commit

Permalink
📮 fix(react-hook-form#11239): Set fields disabled state based on form…
Browse files Browse the repository at this point in the history
… and field disabled (react-hook-form#11241)

* fix(react-hook-form#11239): Set fields disabled state based on form and field disabled prop

* fix(react-hook-form#11239): If-check and unit test

* Update createFormControl.ts

---------

Co-authored-by: Thomas De Bock <thomas.de.bock@persgroep.net>
Co-authored-by: Beier (Bill) <bluebill1049@hotmail.com>
  • Loading branch information
3 people authored and rafaelcalhau committed May 5, 2024
1 parent 1763831 commit fc76251
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 5 deletions.
2 changes: 2 additions & 0 deletions app/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import SetValueAsyncStrictMode from './setValueStrictMode';
import { DelayError } from './delayError';
import './style.css';
import FormComponent from './form';
import DisabledFields from "./disabledFields";

const App: React.FC = () => {
return (
Expand Down Expand Up @@ -117,6 +118,7 @@ const App: React.FC = () => {
<Route path="/test" element={<Test />} />
<Route path="/" element={<Welcome />} />
<Route path="/form" element={<FormComponent />} />
<Route path="/disabled" element={<DisabledFields />} />
</Routes>
</BrowserRouter>
);
Expand Down
22 changes: 22 additions & 0 deletions app/src/disabledFields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { useForm } from "react-hook-form";

const toggle = (state: boolean) => !state;

export default function DisabledFields() {
const [formDisabled, setFormDisabled] = React.useState(false);
const [firstDisabled, setFirstDisabled] = React.useState(false);
const [secondDisabled, setSecondDisabled] = React.useState(true);
const { register } = useForm({ disabled: formDisabled });

return (
<form>
<button type="button" onClick={() => setFormDisabled(toggle)}>Toggle form</button>
<button type="button" onClick={() => setFirstDisabled(toggle)}>Toggle Field 1</button>
<button type="button" onClick={() => setSecondDisabled(toggle)}>Toggle Field 2</button>

<input placeholder="Field 1" {...register('first', { disabled: firstDisabled }) } />
<input placeholder="Field 2" {...register('second', { disabled: secondDisabled }) } />
</form>
)
}
11 changes: 8 additions & 3 deletions app/src/welcome/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,19 +210,24 @@ const items: Item[] = [
},
{
title: 'WatchUseFieldArray',
description: 'should behaviour correctly when watching the field array',
description: 'Should behave correctly when watching the field array',
slugs: ['/watch-field-array/normal', '/watch-field-array/default'],
},
{
title: 'WatchUseFieldArrayNested',
description: 'should watch the correct nested field array',
description: 'Should watch the correct nested field array',
slugs: ['/watchUseFieldArrayNested'],
},
{
title: 'Form',
description: 'should validate form and submit the request',
description: 'Should validate form and submit the request',
slugs: ['/form'],
},
{
title: 'Disabled',
description: 'Should behave correctly when disabling form or fields',
slugs: ['/disabled'],
},
];

const Component: React.FC = () => {
Expand Down
36 changes: 36 additions & 0 deletions src/__tests__/useForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2182,6 +2182,42 @@ describe('useForm', () => {
expect(screen.getByTestId('controller')).not.toBeDisabled();
});

it('should disable form inputs separately from its form', async () => {
function App() {
const { register } = useForm({
disabled: false,
defaultValues: {
lastName: '',
firstName: '',
},
});

return (
<form>
<input
{...register('firstName', { disabled: true })}
placeholder="firstName"
/>
<input
{...register('lastName', { disabled: false })}
placeholder="lastName"
/>
</form>
);
}

render(<App />);

await waitFor(() => {
expect(
(screen.getByPlaceholderText('firstName') as HTMLInputElement).disabled,
).toBeTruthy();
expect(
(screen.getByPlaceholderText('lastName') as HTMLInputElement).disabled,
).toBeFalsy();
});
});

it('should be able to disable the entire form', async () => {
const App = () => {
const [disabled, setDisabled] = useState(false);
Expand Down
10 changes: 8 additions & 2 deletions src/logic/createFormControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1085,8 +1085,14 @@ export function createFormControl<
_subjects.state.next({ disabled });
iterateFieldsByAction(
_fields,
(ref) => {
ref.disabled = disabled;
(ref, name) => {
let requiredDisabledState = disabled;
const currentField = get(_fields, name);
if (currentField && isBoolean(currentField._f.disabled)) {
requiredDisabledState ||= currentField._f.disabled;
}

ref.disabled = requiredDisabledState;
},
0,
false,
Expand Down

0 comments on commit fc76251

Please sign in to comment.