0

I am stuck on this for a day now. Have read multiple answers but could not find anything.

My task is simple, I have a page where a user can answer a question.

  • The page will have two editors open(by default). (Found this in a react-quill GitHub discussion).

  • There will be an 'Add step' button which will, of course, add another quill editor below and the user can add as many steps as he/she likes.

  • The editors will have a 'Delete' button alongside it to delete the editors, except for the first two editors.

Now, I want to store the said steps separately in my DB as well, but the onClick on the editor does not have e.target, instead, it just gives the HTML value. Therefore, how can I add editors onClick and separate the value from the multiple editors?

Any direction or hint towards the solution would be appreciated. Thanks.

Ajay Dhiman
  • 103
  • 4

1 Answers1

2

You can have separate values by using Array of Objects.

It can be done by having two separate components,

  1. One for RichText Editor,
  2. A main component that has a state (Array of Objects)

I used react-quill library for text editor and react-bootstrap for styling in the following code. You can replace one or both of them of your choice

Create two components:

 - App.js // Main component
 - ReactQuill.js // Editor component 

ReactQuill.js

    import React from "react";
    import ReactQuill from "react-quill";
    
    import "react-quill/dist/quill.snow.css";
    
    class ReactQuillEditor extends React.Component {
      render() {
        const { response, handleChange } = this.props;
        return (
          <ReactQuill
            style={{ marginTop: "4px" }}
            value={response}
            onChange={handleChange}
          />
        );
      }
    }
    
    export default ReactQuillEditor;

App.js

import { useState } from "react";
import { Button } from "react-bootstrap";

// Editor Component
import Editor from "./components/ReactQuill";

export default function App() {
  const [steps, setStep] = useState([
    {
      step: 1,
      response: ""
    },
    {
      step: 2,
      response: ""
    }
  ]); // For Default Two Inputs

  const handleChange = (value, index) => {

    // Updates, Remove and Replaces an object at index n
    const steptoReplace = steps[index];
    steptoReplace.response = value;

    steps.splice(index, 1);
    steps.splice(index, 0, steptoReplace);

    setStep(steps);
  };

 // Adds an empty entry
  const addStep = () => {
    setStep([
      ...steps,
      {
        step: steps.length + 1,
        response: ""
      }
    ]);
  };

  const reduceStep = () => {
    // To have Two text editor always
    if (steps.length > 2) {
      steps.pop();
      setStep([...steps]);
    }
  };

  const submit = () => {
    // You will have an Array of Objects of all steps
    console.log("steps", steps);
  };

  return (
    <div className="container">
      <h1>Multiple React Quill</h1>
      <div className="mt-4">
        {steps.map((step, index) => (
          <div key={index}>
            Step {index + 1}
            <Editor
              response={step.response}
              handleChange={(value) => handleChange(value, index)}
            />
          </div>
        ))}

        <div className="d-flex mt-4  justify-content-between">
          <Button onClick={addStep}>Add Step </Button>
          <Button onClick={reduceStep}>Remove Step</Button>
        </div>

        <Button className="mt-4" onClick={() => submit()}>
          Submit
        </Button>
      </div>
    </div>
  );
}
Mohamed Ismail
  • 367
  • 1
  • 7
  • Thanks for this @Mohamed. I wont be able to test the solution for a day or two, but will def get back if this works or if I have any doubts regarding this. – Ajay Dhiman Aug 22 '21 at 12:18
  • 1
    This works, just one thing: I used `value = {response || ''}` in `Editor.js` because I was accessing the value of component before `onChange` is called. Thanks for your time. – Ajay Dhiman Sep 03 '21 at 05:59