rescriptbr / reform

📋 Reasonably making forms sound good
https://rescript-reform.netlify.app/
MIT License
353 stars 41 forks source link

feat(nested-errors,custom-errors): add nested errors for field array #151

Closed painedpineapple closed 4 years ago

painedpineapple commented 4 years ago

Add the ability for fields within a field array to have their own validation and errors.

Add the option to add a custom error message for each validation schema.

fakenickels commented 4 years ago

this is very cool! Will review it ASAP

painedpineapple commented 4 years ago

If it's helpful, here's an example of how NestedErrors are being used:

Form init and Validation schema:

/** InviteUsersForm.re **/
open ReForm;
open ReSchema;

module AuthedCompanyInviteUsersLenses = [%lenses
  type state = {
    message: string,
    users: array(invitee),
  }
];

module Form = ReForm.Make(AuthedCompanyInviteUsersLenses);

let schema =
  Form.Validation.Schema([|
    Custom(
      Users,
      ({users}) =>
        if (users->Array.length < 1) {
          Error("Users are required.");
        } else {
          let errors =
            users->Belt.Array.reduceWithIndex([||], (errors, user, index) =>
              if (user.id == "") {
                Belt.Array.concat(
                  errors,
                  [|{name: "email", index, error: "Email is required"}|],
                );
              } else if (!Validate.email(user.id)) {
                Belt.Array.concat(
                  errors,
                  [|{name: "email", index, error: "Invalid Email"}|],
                );
              } else {
                errors;
              }
            );

          if (errors->Array.length > 0) {
            NestedErrors(errors);
          } else {
            Valid;
          };
        },
    ),
  |]);

/** FieldError.re **/
[@react.component]
let make = (~error, ~index=None, ~name=None) =>
  switch (error, index, name) {
  | (Ok, _, _) => React.null
  | (Errors(errors), Some(index), Some(name)) =>
    switch (
      errors
      |> Js.Array.find(error => error.index == index && error.name == name)
    ) {
    | None => React.null
    | Some(error) =>
      <Alert type_=`error className="error-container">
        error.error->React.string
      </Alert>
    }
  | (Error(error), _, _) =>
    <Alert type_=`error className="error-container">
      error->React.string
    </Alert>
  };

/** Usage of FormError (use this within loop of array fields to get accurate error)**/
<FieldError
    error={form.getFieldErrorState(Field(Users))}
    index={Some(index)}
    name={Some("userRoleName")}
/>
fakenickels commented 4 years ago

Sorry about the delay @thislogancall, will pick up the discussion now

fakenickels commented 4 years ago

Picked up at #171