0

I am working on a page have two sections. In one section we upload image and can increase the number of input, in the other section we will preview the image.

I don't know I am not getting the right id that I want to edit. we can add more fields on click of button and remove then at the end post data at api endpoint?

RightSection

const RightSection = ({ inputImage, setInputImage }) => {
  const handleAddFields = () => {
    if (inputImage.length <= 9) {
      const values = [...inputImage];
      values.push({
        id: values.length + 1,
        name: `Drop Image ${values.length + 1} Here`,
      });
      setInputImage(values);
    }
  };

  const handleRemoveFields = () => {
    if (inputImage.length > 3) {
      const values = [...inputImage];
      values.splice(values.length - 1, 1);
      setInputImage(values);
    }
  };

  const handleInputChange = (id, event) => {
    console.log(id, event.target.id, "=====");
    const newInputFields = inputImage.map((i) => {
      if (id === i.id) {
        i.url = URL.createObjectURL(event.target.files[0]);
        i.name = event.target.files[0].name;

        // push image object in array
        setInputImage([
          ...inputImage,
          {
            id: id,
            url: URL.createObjectURL(event.target.files[0]),
            name: event.target.files[0].name,
          },
        ]);
      }
      return i;
    });
    setInputImage(newInputFields);
  };

  console.log(inputImage);

  return (
    <>
      <div id="right" className="flex">
        <div className="margin">
          <div className="inlineflex">
            <H1>Background Image</H1>
            <div>
              <AddIcon onClick={handleAddFields} />
              <RemoveIcon onClick={handleRemoveFields} />
            </div>
          </div>
        </div>

        <div
          style={{
            margin: "0 auto",
            position: "relative",
            width: "80%",
          }}
        >
          {inputImage.map((inputField, index) => (
            <FileInput key={index}>
              <label
                htmlFor={inputField.id}
                onClick={(e) => {
                  console.log("click", index + 1);
                }}
              >
                {inputField.name}
              </label>
              <input
                id={index + 1}
                onChange={(event) => handleInputChange(inputField.id, event)}
                accept="image/*"
                type="file"
              />
            </FileInput>
          ))}
        </div>
      </div>
    </>
  );
};

LeftSection

const LeftSection = ({ inputImage }) => {
  return (
    <>
      <div id="left" className="flex">
        <div className="margin">
          <H1>Preview</H1>
        </div>

        <Grid>
          {Array.isArray(inputImage) &&
            inputImage.map((item, index) => {
              if (item?.url?.includes("http") || item?.url?.includes("https")) {
                return (
                  <div key={index}>
                    <img src={item?.url} alt={item?.name} />
                  </div>
                );
              }
            })}
        </Grid>
      </div>
    </>
  );
};

BackgroundImage

let initaValue = [
  { id: 1, name: "Drop Image 1 Here", url: "" },
  { id: 2, name: "Drop Image 2 Here", url: "" },
  { id: 3, name: "Drop Image 3 Here", url: "" },
];

const BackgroundImage = () => {
  const [inputImage, setInputImage] = useState(initaValue);

  return (
    <>
      <Container>
        <RightSection inputImage={inputImage} setInputImage={setInputImage} />
        <LeftSection inputImage={inputImage} setInputImage={setInputImage} />
      </Container>
    </>
  );
};

export default BackgroundImage;

I think there is some issue with the handleInputChange function on the RightSection component.

Somehow I am not able to update the item with the correct id in the array.

Is there any other efficient solution for this problem?

RubenSmn
  • 4,091
  • 2
  • 5
  • 24

1 Answers1

0

After doing some work I found out the solution to the problem by myself here is a code solution that works 100% fine for me

const EditContainer = ({ images, setImages }) => {
    // generate new  input field dynamically
    const addnewInputField = () => {`enter code here`
        const newImages = [...images];
        newImages.push({
            id: new Date().getTime().toString(),
            type: "input",
            imageData: {
                id: Math.random().toString(36).substr(2, 9),
                src: "",
                alt: "",
            },
        });
        setImages(newImages);
    };

    // remove the last field of input also the last image from preview 
    const removeInputField = () => {
        // remove last element
        if (images.length === 0) return;
        const newImages = [...images];
        newImages.pop();
        setImages(newImages);
    };

    // update the image in the input field
    const updateImage = (e, id) => {
        const files = e.target.files;
        const newImages = [...images];
        for (let i = 0; i < files.length; i++) {
            const file = files[i];
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => {
                const index = newImages.findIndex((image) => image.id === id);
                newImages[index].imageData = {
                    src: reader.result,
                    alt: file.name,
                };
                setImages(newImages);
            };
        }
    };

    return (
        <>
            <h1>Edit</h1>
            <div>
                <button onClick={addnewInputField}>Add New Input Field</button>
                <button onClick={removeInputField}>Remove Input Field</button>
            </div>

            {Array.isArray(images) &&
                images.length > 0 &&
                images.map((image, index) =>
                    image.type === "input" ? (
                        <div key={index} id={image.id}>
                            <input
                                accept="image/*"
                                type="file"
                                onChange={(e) => updateImage(e, image.id)}
                            />
                        </div>
                    ) : null
                )}
        </>
    );
};

const PreviewContainer = ({ images, setImages }) => {
    return (
        <>
            <h1>Preview</h1>

            {Array.isArray(images) &&
                images.length > 0 &&
                images.map(
                    (image, index) =>
                        image.type === "input" &&
                        image.imageData.src &&
                        image.imageData.alt && (
                            <div key={index} id={image.imageData.id}>
                                <img
                                    src={image.imageData.src}
                                    alt={image.imageData.alt}
                                    width={400}
                                    height={400}
                                    objectFit="contain"
                                />
                                <button
                                    onClick={() => {
                                        const newImages = [...images];
                                        newImages.splice(index, 1);
                                        setImages(newImages);
                                    }}
                                >
                                    Remove
                                </button>
                            </div>
                        )
                )}
        </>
    );
};

**Main Component**

const StackOverFlow = () => {
    // for storing images state
    const [images, setImages] = useState([]);
    return (
        <>
            <h1>Main Componet</h1>
            <div>
                <EditContainer images={images} setImages={setImages} />  
                <PreviewContainer images={images} setImages={setImages} />
            </div>
        </>
    );
};

export default StackOverFlow;