Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider adding a way to get/list all the fields and iterate them ? #10

Open
elnygren opened this issue Apr 9, 2019 · 3 comments
Open

Comments

@elnygren
Copy link
Contributor

elnygren commented Apr 9, 2019

Sometimes when working with forms one might want to loop over all the fields and render any errors they have.

Perhaps this library could generate some kind utilities for this in addition to getters&setters of individual fields?

For example maybe I'd like to do this in onSubmitFail of reforms:

/** Handle failures detecred *before* onSubmit (mutation call).ShiftsListGraphQL
    Useful for displaying errors from local validations of ShiftForm. */
let onSubmitFail = ({state}: ShiftForm.onSubmitAPI) => {
  Js.log4("onSubmitFail", state.values, state.formState, state.fieldsState)

  let collectErrorString = field =>
    ShiftForm.getFieldState(~schema, ~values=state.values, ~field)
    ->Belt.Option.map((_, fieldState) =>
        switch (fieldState) {
        | ShiftForm.Error(s) => Some(s)
        | _ => None
        }
      );

  // build these into Js.Dict along their errors to render something to the user
  // eg; "there are errors in these fields"
  collectErrorString(Field(Name))
  collectErrorString(Field(BrandId))
  collectErrorString(Field(Is_draft))
  collectErrorString(Field(ShiftId))
  collectErrorString(Field(Shift_visibility))
  collectErrorString(Field(Contract_type))
  collectErrorString(Field(Matchmaking_industry))
  collectErrorString(Field(Matchmaking_category))
  collectErrorString(Field(Name))
  collectErrorString(Field(Description))
  collectErrorString(Field(LocationId))
  collectErrorString(Field(Custom_address))
  collectErrorString(Field(Languages))
  collectErrorString(Field(Requirements))
  collectErrorString(Field(Cover_photo))
  collectErrorString(Field(Schedule_type))
  collectErrorString(Field(Pricing_type))
  collectErrorString(Field(Rate_hourly_amount))
  collectErrorString(Field(Rate_fixed_amount))
  collectErrorString(Field(Times))
  collectErrorString(Field(Cnt))

};

however, the code can get quite tedious quite fast with larger forms.

Or maybe I should be approaching this problem differently?

@fakenickels
Copy link
Contributor

Actually this is already ReForm does internally, the trick is to iterate over the validation schema!
https://github.com/Astrocoders/reform/blob/master/packages/bs-reform/src/ReFormNext.re#L57

To have a way to iterate over the list of GADTs directly is very cumbersome, see here https://discuss.ocaml.org/t/packing-gadt-constructors-in-iterable-data-structure/2678/4

@fakenickels
Copy link
Contributor

Sorry for the late response 😅
Thanks for using ReForm, FYI we are almost getting ready to launch ReFormNext as stable with a hooks API

@fakenickels
Copy link
Contributor

I've been using this pattern:

  let mergeWholeState =
      (
        formState,
        ~schema:
           ReSchema.Make(OnboardingProfileFormTypes.StateLenses).Validation.schema(
             option(ProfileFastForm.meta),
           ),
      ) => {
    open OnboardingProfileFormTypes.StateLenses;

    let Schema(schema) = schema;

    let changeField = field => {
      let currentState = currentWholeFormState->React.Ref.current;
      let newState = currentState->set(field, formState->get(field));
      currentWholeFormState->React.Ref.setCurrent(newState);
    };

    schema->Belt.Array.forEach(validator => {
      switch (validator) {
      | ProfileFastForm.Form.Validation.StringNonEmpty({field})
      | ProfileFastForm.Form.Validation.StringRegExp({field})
      | ProfileFastForm.Form.Validation.StringMin({field})
      | ProfileFastForm.Form.Validation.StringMax({field})
      | ProfileFastForm.Form.Validation.Email({field}) =>
        let currentState = currentWholeFormState->React.Ref.current;
        let newState =
          currentState->set(field, formState->get(field)->Js.String.trim);
        currentWholeFormState->React.Ref.setCurrent(newState);
      | ProfileFastForm.Form.Validation.IntMin({field})
      | ProfileFastForm.Form.Validation.IntMax({field}) => changeField(field)
      | ProfileFastForm.Form.Validation.FloatMin({field})
      | ProfileFastForm.Form.Validation.FloatMax({field}) =>
        changeField(field)
      | ProfileFastForm.Form.Validation.Custom({field}) => changeField(field)
      | ProfileFastForm.Form.Validation.NoValidation({field}) =>
        changeField(field)
      }
    });

    Hooks.OnboardingFormData.persist(currentWholeFormState->React.Ref.current)
    |> ignore;
  };

though the list of validators is pretty huge it's mostly boilerplate and if you are using ocamllsp you can use the destruct code action to generate it automatically for you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants