0

I have this data where every time a user wants to add more color, it will add colors in the field color. Something like this: color: ["blue","green","yellow"]or an array. As of now, if I'll add more colors, it will just override the first color.

How can I update the field color without overriding the previous values?

index.js

import React from "react";
import { useForm } from "react-hook-form";
import FieldArray from "./fieldArray";
import ReactDOM from "react-dom";

import "./styles.css";
import { Button } from "@mui/material";

const defaultValues = {
  test: [
    {
      product: "",
      nestedArray: [{ size: "", color: "", design: "" }]
    }
  ]
};

function App() {
  const {
    control,
    register,
    handleSubmit,
    getValues,
    errors,
    reset,
    setValue
  } = useForm({
    defaultValues
  });
  const onSubmit = (data) => console.log("data", data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <h1>Array of Array Fields</h1>
      <p>
        The following example demonstrate the ability of building nested array
        fields.
      </p>

      <FieldArray
        {...{ control, register, defaultValues, getValues, setValue, errors }}
      />

      <button type="button" onClick={() => reset(defaultValues)}>
        Reset
      </button>

      <Button type="submit">Submit</Button>
      {/* <input type="submit" /> */}
    </form>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

fieldArray.js

import React from "react";
import { useFieldArray } from "react-hook-form";
import NestedArray from "./nestedFieldArray";
import { InputLabel } from "@mui/material";
import Size from "./Drop_drowns/Size";

let renderCount = 0;

export default function Fields({ control, register, setValue, getValues }) {
  const { fields, append, remove, prepends } = useFieldArray({
    control,
    name: "test"
  });

  renderCount++;

  const productItems = [
    { label: "Shirt1", value: "Shirt1" },
    { label: "Shirt2", value: "Shirt2" },
    { label: "Shirt3", value: "Shirt3" },
    { label: "Shirt4", value: "Shirt4" }
  ];

  const menuItems = [
    { label: "S", value: "S" },
    { label: "M", value: "M" },
    { label: "L", value: "L" }
  ];

  return (
    <>
      <ul>
        {fields.map((item, index) => {
          return (
            <li key={item.id}>
              <label>Item {index + 1}</label>
              <InputLabel id="demo-simple-select-label">Product</InputLabel>
              <Size
                name={`test[${index}].product`}
                menuItems={productItems}
                refer={register({ required: true })}
                defaultValue={item.product}
                control={control}
              />
              <InputLabel id="demo-simple-select-label">Size</InputLabel>
              <Size
                name={`test[${index}].size`}
                menuItems={menuItems}
                refer={register({ required: true })}
                defaultValue={item.size}
                control={control}
              />
              <InputLabel id="demo-simple-select-label">color</InputLabel>
              <Size
                name={`test[${index}].color`}
                menuItems={menuItems}
                refer={register({ required: true })}
                defaultValue={item.color}
                control={control}
              />
              <button type="button" onClick={() => remove(index)}>
                Delete
              </button>
              <NestedArray nestIndex={index} {...{ control, register }} />
            </li>
          );
        })}
      </ul>

      <section>
        <button
          type="button"
          onClick={() => {
            append({ name: "append" });
          }}
        >
          Add product
        </button>
      </section>

      <span className="counter">Render Count: {renderCount}</span>
    </>
  );
}

nestedFieldArray

import React from "react";
import { useFieldArray } from "react-hook-form";
import Size from "./Drop_drowns/Size";
import { InputLabel } from "@mui/material";

//only changed here the name nestedArray to variations

export default ({ nestIndex, control, register }) => {
  const { fields, remove, append } = useFieldArray({
    control,
    name: `test[${nestIndex}].variantion`
  });

  const menuItems = [
    { label: "S", value: "S" },
    { label: "M", value: "M" },
    { label: "L", value: "L" }
  ];

  const colorItems = [
    { label: "red", value: "red" },
    { label: "green", value: "green" },
    { label: "blue", value: "blue" }
  ];

  return (
    <div>
      {fields.map((item, k) => {
        return (
          <div key={item.id} style={{ marginLeft: 20 }}>
            {/* <Size
              name={`test[${nestIndex}].variantion[${k}].size`}
              menuItems={menuItems}
              refer={register({ required: true })}
              defaultValue={item.size}
              control={control}
            /> */}
            <InputLabel id="demo-simple-select-label">Color</InputLabel>

            <Size
              name={`test[${nestIndex}].color`}
              menuItems={colorItems}
              refer={register({ required: true })}
              defaultValue={item.color}
              control={control}
            />

            {/* <input
              name={`test[${nestIndex}].variantion[${k}].color`}
              ref={register({ required: true })}
              defaultValue={item.field}
              style={{ marginRight: "25px" }}
            /> */}

            <button type="button" onClick={() => remove(k)}>
              Delete Colors
            </button>
          </div>
        );
      })}

      <button
        type="button"
        onClick={() =>
          append({
            field1: "field1",
            field2: "field2"
          })
        }
      >
        Add Colors
      </button>

      <hr />
    </div>
  );
};
JS3
  • 1,623
  • 3
  • 23
  • 52
  • For each Shirt Size, you can select multiple colors? So does multiple colors means multiple shirts? Or 1 shirt/size with multiple colors? – Someone Special Feb 23 '22 at 10:47

3 Answers3

1

Seems like what you're trying to achieve with colors is providing one or more options the user can choose from. The way it is now with adding a field for each may not be the best approach.

A more common method would be checkboxes where you can select one or many. Here's a blog post about this in React. While this discusses a cash register, the concept of adding the number values can be applied to the color values to form an array of the ones selected.

If you would like to continue using fields, the root cause of the issue in your current code is that each field for a color is mapped to the color in the output object, so if there's multiple the last one wins. There are a few ways to go about fixing this:

  • bring in a new dependency like Field.Group component of React Advanced Form or something like react-fieldset to modify color to group/nest the fields underneath it
  • write your own submit handleSubmit function where you could retrieve and combine the color fields into one
  • remove the concept of a singular color and have it be numeric (e.g. color1, color2, etc.)
Blake Gearin
  • 175
  • 1
  • 10
0

In defaultValues change nestedArray as map in which declare color viables as array and something like this...

var defaultValues = {
  test: [
    {
      product: "",
      nestedArray: { size: ["S","M","L"], color: ["blue","green","yellow"], design: "" }
    }
  ]
};

once user adds color add new color value in that color Array.

ViKi Vyas
  • 691
  • 5
  • 16
0

If you want to save new values and do not override old one, use color as a list and append to it. Save all values to list. Use all values or one specific.

const arr = [
  "blue"
];

//add new value
arr.push("red")

console.log("VALUES", arr);
console.log("FIRST ITEM", arr[0]);
console.log("LAST ITEM", arr[arr.length - 1])
aarnas
  • 116
  • 3