suid icon indicating copy to clipboard operation
suid copied to clipboard

Modular Forms seems incompatible with SUID

Open NightmanCZ90 opened this issue 2 years ago • 6 comments

Hello, I started SolidJS project with SUID and for forms I wanted to use Modular Forms for forms validation. But I got stuck on an issue, when passed field props do not match with TextField's props. Below is an example of TextField usage with Modular Forms.

It seems that your event handlers design does not match up with the default ones (for ).

       <Form of={loginForm} onSubmit={handleSubmit}>
          <Field
            of={loginForm}
            name="email"
          >
            {(field) =>
                <TextField
                  {...field.props}
                  type="email"
                  // Reassign onInput and onChange, overwrite events
                  onInput={(e) => field.props.onInput({ ...e, currentTarget: { ...e.currentTarget, value: e.target.value } }) }
                  onChange={(e) => field.props.onInput(e)}
                  error={Boolean(field.error)}
                  helperText={field.error}
                  value={field.value || ''}
                />}
          </Field>
          <div class="signin-form--button">
            <Button
              type="submit"
              fullWidth
              color="secondary"
              variant="contained"
            >
              Sign in
            </Button>
          </div>
        </Form>

So far I have used this workaround below. But my question is whether there is a correct way to use these libraries together?

import { FieldElement } from "@modular-forms/solid";
import { JSX } from "solid-js";

export const remapFieldProps = (fieldProps: {
  name: string;
  ref: (element: FieldElement) => void;
  onInput: JSX.EventHandler<FieldElement, InputEvent>;
  onChange: JSX.EventHandler<FieldElement, Event>;
  onBlur: JSX.EventHandler<FieldElement, FocusEvent>;
}) => ({
  name: fieldProps.name,
  inputRef: fieldProps.ref,
  onBlur: fieldProps.onBlur,
  onChange: (e: any) => { fieldProps.onChange(e); fieldProps.onInput(e) }
});

=====================
<Field
  of={loginForm}
  name="email"
  validate={[
     required('Please enter your email.'),
     email('Please enter a valid email address.')
  ]}
>
  {(field) =>
    <TextField
      inputProps={{ ...remapFieldProps(field.props) }}
      type="email"
      value={field.value || ''}
      error={Boolean(field.error)}
      helperText={field.error}
    />}
</Field>

NightmanCZ90 avatar Mar 16 '23 23:03 NightmanCZ90

Could you share a link with the code at stackblitz?

If you want to use uncontrolled components (controlled by @modular-forms/solid) you should not use the value and onInput properties together.

  • Controlled components: value + onChange.
  • Uncontrolled components: defaultsValue + onChange/onInput.

juanrgm avatar Mar 17 '23 07:03 juanrgm

@juanrgm you are right. Thanks for your input. The following code example works:

<Field of={form} name="email">
  {(field) => (
    <TextField
      variant="outlined"
      inputProps={{
        ...field.props,
        onChange: field.props.onInput,
      }}
    />
  )}
</Field>

For what reason do you use the name onChange instead of onInput as usual in SolidJS? And then what is the default onChange event of SolidJS on the input element?

fabian-hiller avatar Mar 17 '23 10:03 fabian-hiller

For what reason do you use the name onChange instead of onInput as usual in SolidJS? And then what is the default onChange event of SolidJS on the input element?

Because the concept controlled component does not exist natively, it's inherited from React, where the behavior of the native onChange is replaced for supporting the controlled value.

juanrgm avatar Mar 21 '23 00:03 juanrgm

I understand the background with React. However, the name has nothing to do with whether the field can be controlled or am I wrong? onInput might make more sense for the SolidJS implementation since that's the name most users expect.

fabian-hiller avatar Mar 21 '23 00:03 fabian-hiller

All controlled components follow the same pattern (value, defaultsValue, onChange).

I would need a proof of concept in React with MUI to see if there are any differences with SUID (example: input event is not fired after change).

juanrgm avatar Mar 31 '23 18:03 juanrgm