Как провести валидацию в многоэтапной форме с помощью React - PullRequest
4 голосов
/ 13 июля 2020

Я работаю над сценарием, в котором мне нужно создать многоступенчатую форму, которую я уже сделал, а также часть проверки. Я использую react-hook-form для проверки.

У меня многошаговая форма:

  • в первой форме у меня есть несколько полей и один переключатель
  • by переключатель по умолчанию установлен для auto generated pass, поэтому в этом случае мне нечего делать
  • , второй - let me create a password, поэтому в этом случае будет отображаться одно поле ввода, и пользователь создаст пароль

Проблема

В моей окончательной форме я выполняю проверку, как показано ниже:

{
  fields: ["uname", "email", "password"], //to support multiple fields form
  component: (register, errors, defaultValues) => (
    <Form1
      register={register}
      errors={errors}
      defaultValues={defaultValues}
    />
  )
},

Итак, чтобы проверить uname, адрес электронной почты и пароль Я передаю значения, как указано выше.

Но когда переключатель установлен на автоматически сгенерированный пароль, он все еще обрабатывает проверку, я нажимаю «Далее», и это не происходит из-за поля пароля.

И если я отмечу переключатель как let me create the password, он перейдет к следующей форме, а когда я вернулся, щелкнув back, он снова перейдет к auto generated password и не удерживает предыдущее состояние. Для других полей ввода он обрабатывает предыдущие значения, но не в случае сценария с переключателем.

Моя полная песочница рабочего кода

Ответы [ 2 ]

1 голос
/ 15 июля 2020

Ответ 1 Причина в том, что вы fields: ["uname", "email", "password"] исправлено, password всегда нужно принимать для проверки. Решение Необходимо сохранить состояние Form1 в приложении, чтобы вы могли проверить, находится ли состояние auto generated password при удалении пароля из списка

Приложение. js

... other code
// need to move state and function form Form to app
const [show_input, setshow_input] = useState(false);

  const createInput = () => {
    setshow_input(true);
  };
  const auto_text = () => {
    setshow_input(false);
  };
  const forms = [
    {
      // validate based on show_input state
      fields: show_input ? ["uname", "email", "password"] : ["uname", "email"], //to support multiple fields form
      component: (register, errors, defaultValues) => (
        <Form1
          register={register}
          errors={errors}
          defaultValues={defaultValues}
          auto_text={auto_text}
          createInput={createInput}
          show_input={show_input}
        />
      )
    },
    {
      fields: ["lname"],
      component: (register, errors, defaultValues) => (
        <Form2
          register={register}
          errors={errors}
          defaultValues={defaultValues}
        />
      )
    },
    {
      component: (register, errors, defaultValues) => (
        <Form3
          register={register}
          errors={errors}
          defaultValues={defaultValues}
        />
      )
    }
  ];
... other code

Ответ 2 Когда вы go следующий, Form1 отключается, поэтому его состояние уничтожается. Когда вы сохраняете состояние Form1 в приложении. js, вы тоже исправите эту проблему

Бонус: предпочтительнее использовать camalCase (например: showInput), а не подчеркивание (show_input)

Редактировать serene-fast-jj8br

0 голосов
/ 15 июля 2020

Основная проблема заключается в том, что вы визуализируете формы условно, поэтому все предыдущие значения формы удаляются. Для этого нужно оставить все формы смонтированными и просто использовать display: none или display: block в зависимости от того, какая форма выбрана. Таким образом, все значения будут сохраняться всякий раз, когда вы go переходите к следующей или предыдущей форме или отправляете форму.

Вторая проблема заключается в том, что вы не удалили поле пароля, когда оно отключено, поэтому при вызове moveToNext аргумент valid в обратном вызове triggerValidation всегда ложен. Я исправил это, установив поля для Form1 условно в зависимости от того, виден ли ввод пароля или нет.

Третья проблема, которую вы используете defaultValues не по назначению. Вы можете получить текущие значения формы, используя getValues(), который вернет все текущие значения формы.

Я установил значение по умолчанию для поля uname просто в качестве примера, чтобы показать вам, как defaultValues должен

вы можете проверить полное решение здесь: https://codesandbox.io/s/fragrant-forest-75pzs?file= / src / App. js

вот все измененные файлы:

Прил. js

import React, { useState } from "react";
import Form1 from "./components/Form1";
import Form2 from "./components/Form2";
import Form3 from "./components/Form3";
import { useForm } from "react-hook-form";

function MainComponent() {
  const {
    register,
    triggerValidation,
    defaultValues,
    errors,
    getValues
  } = useForm({
    // You can set default values here
    defaultValues: {
      uname: "Lol"
    }
  });
  console.log("Errors: ", errors);
  const [currentForm, setCurrentForm] = useState(0);

  // control password input visibility and Form1 fields
  const [passwordVisible, setPasswordVisible] = useState(false);

  const showPassword = () => {
    setPasswordVisible(true);
  };
  const hidePassword = () => {
    setPasswordVisible(false);
  };

  const forms = [
    {
      fields: passwordVisible
        ? ["uname", "email", "password"]
        : ["uname", "email"],
      component: (register, errors) => (
        <Form1
          // a key is needed to render a list
          key={0}
          // this will be used to set the css display property to block or none on each form
          shouldDisplay={currentForm === 0}
          register={register}
          errors={errors}
          showPassword={showPassword}
          hidePassword={hidePassword}
          passwordVisible={passwordVisible}
        />
      )
    },
    {
      fields: ["lname"],
      component: (register, errors) => (
        <Form2
          key={1}
          shouldDisplay={currentForm === 1}
          register={register}
          errors={errors}
        />
      )
    },
    {
      component: (register, errors) => (
        <Form3
          key={2}
          shouldDisplay={currentForm === 2}
          register={register}
          errors={errors}
          values={getValues()}
        />
      )
    }
  ];

  const moveToPrevious = () => {
    triggerValidation(forms[currentForm].fields).then(valid => {
      if (valid) setCurrentForm(currentForm - 1);
    });
  };

  const moveToNext = () => {
    triggerValidation(forms[currentForm].fields).then(valid => {
      if (valid) setCurrentForm(currentForm + 1);
    });
  };

  const prevButton = currentForm !== 0;
  const nextButton = currentForm !== forms.length - 1;
  const handleSubmit = e => {
    console.log("whole form data - ", getValues());
  };
  return (
    <div>
      <div className="progress">
        <div>{currentForm}</div>
      </div>

      {forms.map(form => form.component(register, errors))}

      {prevButton && (
        <button
          className="btn btn-primary"
          type="button"
          onClick={moveToPrevious}
        >
          back
        </button>
      )}
      {nextButton && (
        <button className="btn btn-primary" type="button" onClick={moveToNext}>
          next
        </button>
      )}

      {currentForm === 2 && (
        <button
          onClick={handleSubmit}
          className="btn btn-primary"
          type="submit"
        >
          Submit
        </button>
      )}
    </div>
  );
}

export default MainComponent;

Форма1

import React from "react";

function Form1({
  register,
  errors,
  shouldDisplay,
  passwordVisible,
  showPassword,
  hidePassword
}) {
  return (
    <div style={{ display: shouldDisplay ? "block" : "none" }}>
      <form autoComplete="on">
        <br />
        <div className="form-group">
          <label>User name</label>
          <input type="text" name="uname" ref={register({ required: true })} />
          {errors.uname && <span>required</span>}
          <label>Email</label>
          <input type="email" name="email" ref={register({ required: true })} />
          {errors.email && <span>required</span>}
        </div>
        <div>
          <div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
            <label className="form_label">Password</label>
            <div className="form-check">
              <label>
                <input
                  type="radio"
                  name="auto_pass"
                  id="Radios1"
                  value="auto_pass"
                  className="form-check-input"
                  defaultChecked={true}
                  onChange={hidePassword}
                />
                Auto generated password
              </label>
            </div>
            <div className="form-check">
              <label>
                <input
                  type="radio"
                  name="auto_pass"
                  id="Radios2"
                  value="let_me"
                  className="form-check-input"
                  onChange={showPassword}
                />
                Let me create the password
              </label>
            </div>
          </div>
          {passwordVisible && (
            <div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
              <label className="form_label">Password</label>
              <input
                type="password"
                name="password"
                className="form-control"
                ref={register({ required: true })}
              />
              {errors.password && (
                <span className="text-danger">Password is reguired</span>
              )}
            </div>
          )}
        </div>
      </form>
    </div>
  );
}

export default Form1;

Форма2

import React from "react";

function Form2({ register, errors, shouldDisplay }) {
  return (
    <div style={{ display: shouldDisplay ? "block" : "none" }}>
      <form autoComplete="on">
        <br />
        <div className="form-group">
          <label>User last name</label>
          <input type="text" name="lname" ref={register({ required: true })} />
          {errors.lname && <span>required</span>}
        </div>
      </form>
    </div>
  );
}

export default Form2;

Форма3

import React from "react";

function Form3({ values, shouldDisplay }) {
  return (
    <div style={{ display: shouldDisplay ? "block" : "none" }}>
      <h3>Want to display all values here like below</h3>
      {Object.entries(values).map(([key, value]) => (
        <p key={key}>
          {key}: {value}
        </p>
      ))}

      <br />
      <p>So that use can check for any Wrong info</p>
    </div>
  );
}

export default Form3;
...