1

I'm trying to change the Inputs that I display based on id state variable that the user can select in a dropdown. It's odd, but after changing the select ID, the Inputs are rendered properly, but it is setting the previous Input value to the new Input. Also, the submit is validating Input that does not exist.

import React, { useState, useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { Button, Form, Label, Input } from "reactstrap";

const App = () => {
  const [id, setID] = useState(1);
  const units = [
    { UnitID: 1, UnitName: "101" },
    { UnitID: 2, UnitName: "102" },
    { UnitID: 3, UnitName: "103" },
    { UnitID: 4, UnitName: "104" }
  ];

  useEffect(() => {
    console.log("ID was updated");
  }, [id]);

  const {
    handleSubmit,
    control,
    setValue,
    formState: { errors }
  } = useForm();

  const handleChangeDeposit = (id) => {
    setValue("id", parseInt(id));
    setID(parseInt(id));
  };

  const resetFields = () => {
    setValue("transactionComment", "");
    setValue("unitID", 0);
  };

  const renderTest = () => {
    switch (parseInt(id)) {
      case id === 3 || id === 5:
        resetFields();
        return (
          <div className="col-sm-3">
            <Label for="transactionComment" className="mr-sm-10">
              Comment
            </Label>
            <Controller
              name="transactionComment"
              control={control}
              rules={{ required: true }}
              defaultValue={""}
              render={({ field }) => (
                <Input {...field} type="text" id="transactionComment" />
              )}
            />
            {errors.transactionComment && (
              <span style={{ color: "red" }} role="alert">
                required
              </span>
            )}
          </div>
        );
      case 11:
        resetFields();
        setValue("transactionComment", "Laundry Room");
        return (
          <div className="col-sm-3">
            <Label for="transactionComment" className="mr-sm-10">
              Comment
            </Label>
            <Controller
              name="transactionComment"
              control={control}
              defaultValue={"Laundry Room"}
              render={({ field }) => (
                <Input
                  {...field}
                  type="text"
                  id="transactionComment"
                  readOnly
                />
              )}
            />
          </div>
        );
      default:
        resetFields();
        return (
          <div className="col-sm-3">
            <Label for="unitID" className="mr-sm-10">
              Unit
            </Label>
            <Controller
              name="unitID"
              control={control}
              rules={{ required: true }}
              defaultValue={0}
              render={({ field }) => (
                <Input {...field} type="select" id="unitID">
                  <option value="0">Select</option>
                  {units.map((obj) => {
                    return (
                      <option key={obj.UnitID} value={obj.UnitID}>
                        {obj.UnitName}
                      </option>
                    );
                  })}
                </Input>
              )}
            />
            {errors.unitID && (
              <span style={{ color: "red" }} role="alert">
                required
              </span>
            )}
          </div>
        );
    }
  };

  const submitForm = (data) => {
    if ([3, 5].includes(id) && data.transactionComment === "") {
      alert("Transaction Comment is require");
      return;
    }
    if (![3, 5].includes(id) && parseInt(data.unitID) === 0) {
      alert("Unit is required.");
      return;
    }
    alert("Updated!");
  };

  return (
    <div className="row">
      <div className="col-sm-12 col-md-12 col-xl-12">
        <Form onSubmit={handleSubmit(submitForm)}>
          <div className="row">
            <div className="col-sm-3">
              <Label for="id" className="mr-sm-10">
                Select
              </Label>
              <Controller
                name="id"
                control={control}
                rules={{ required: true }}
                defaultValue={1}
                render={({ field }) => (
                  <Input
                    {...field}
                    type="select"
                    id="id"
                    onChange={(e) => handleChangeDeposit(e.target.value)}
                  >
                    <option value="0">Select</option>
                    <option value="3">Option 3</option>
                    <option value="5">Option 5</option>
                    <option value="11">Option 11</option>
                    <option value="15">Others</option>
                  </Input>
                )}
              />
              {errors.id && (
                <span style={{ color: "red" }} role="alert">
                  required
                </span>
              )}
            </div>
            {renderTest()}
            <div className="col-sm-3">
              <Label for="memo" className="mr-sm-10">
                Memo
              </Label>
              <Controller
                name="memo"
                control={control}
                render={({ field }) => (
                  <Input
                    {...field}
                    type="text"
                    name="memo"
                    placeholder="12345"
                  />
                )}
              />
            </div>
          </div>
          <Button type="submit">Update</Button>
        </Form>
      </div>
    </div>
  );
};

export default App;

Here is the SandBox: https://codesandbox.io/s/serene-greider-z3xpd?file=/src/App.js:0-5426

Thanks

3
  • I tried using your codesandbox but all it seems to do it alert that a comment is required. Can you update your question to include a set of reproduction steps for whatever the issue is? Commented Jul 19, 2021 at 23:39
  • That's the issue. The comment should not be required when it's not rendered Commented Jul 20, 2021 at 14:37
  • Can you update your question to include a set of reproduction steps for whatever the issue is, and rephrase your title and description so that it is clearer the issue is with field/form validation and not whatever "React change Input elements based on state variable" means? I'll take a deeper look at your sandbox. Commented Jul 20, 2021 at 15:36

1 Answer 1

2

Issue

The issue is in your renderTest function, you've a malformed switch case.

const renderTest = () => {
  switch (parseInt(id)) {
    case id === 3 || id === 5:
      ...

    case 11:
      ...

    default:
      ...
  }
};

id === 3 || id === 5 resolves to a boolean but you are switching on id which is one of the values 0, 3, 5, 11, and 15. Since none of the id values is true/false the default case is rendered.

When submitForm is invoked the "comment" validation is checked.

if ([3, 5].includes(id) && data.transactionComment === "") {
  alert("Transaction Comment is require");
  return;
}

Solution

Fix the switch statement to use two distinct cases for id 3 and 5.

const renderTest = () => {
  switch (parseInt(id)) {
    case 3:
    case 5:
      ...

    case 11:
      ...

    default:
      ...
  }
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.