0

I have dynamic input fields that come from my database. generating the input fields aren't a problem. however once the user enters the information, they may want to come back and change the input. I am having trouble with the edit component. It seems that if I put anything in the value property, the text in the field will not change. For clarity, lets say I have 5 inputs but the user only fills in 2. I want their data to display in the right inputs. Here is what I am doing.

  useEffect(() => {
    fetchPlatformInputs();
  }, []);

const fetchPlatformInputs = async () => {

  const fetchInputs = async () => {
    const fetchedInputs = await API.graphql({
      query: sortInputsByType,
      variables: { type: "*", sortDirection: "ASC" },
    });

  const { items } = fetchedInputs.data.sortInputsByType;  <--- the input fields

// Then the user's input for each field is held in context (which is derived from the user table) so I loop over both object arrays to create one object array of dynamic inputs with user data.

contextUser.inputData.map((contextData) => {
      for(const item of items) {
        if (contextData.inputType === item.inputType) {
         item.inputData = contextData.inputData;
        }
      }
    });

// Now I have an object array that joined the dynamic inputs and user data and I set put that into state.  

setPlatformInputs(items);

};

/// that is just a useState combo.  I loop over this variable to create the dynamic inputs.

  const [platformInputs, setPlatformInputs] = useState([]);

//. Okay now for the part I can't figure out.

// here is where I hold the form data:

const [formValues, setFormValues] = useState([]);

// the onchange handler builds an object array for database insertion.

  let handleChange = (e, inputType, inputData, isFabIcon, iconColor, imagePath) => {
    
    setFormValues({
      ...formValues,
      [inputType]: {
        inputType: inputType,
        inputData: inputData,
        isFabIcon: isFabIcon,
        iconColor: iconColor,
        imagePath: imagePath,
      },
    });


    console.log("form values are ", formValues);
  };

//. here are the dynamic fields

 {platformInputs?.length > 0 &&
          platformInputs.map((input, index) => (
            <MDBRow
              className="mx-auto my-2 text-center"
              key={"r" + index + "_" + input.inputType}
            >
              <MDBCol sm="2" key={"c1_" + input.inputType}>
                // image or icon goes here
              </MDBCol>
              <MDBCol sm="10" key={"c2_" + input.inputType}>
                <MDBInput
                  name={["input_" + input.inputType]}
                  label={[capitalizeWords(input.inputType)]}
                  type="text"
                  value={input.inputData}.  <-- here is the problem.  I can't figure out how to display the initial incoming user data and update it with the state formValues variable derived from the onChange handler
                  onChange={(e) =>
                    handleChange(
                      e,
                      input.inputType,
                      input.inputData,
                      input.isFabIcon,
                      input.iconColor,
                      input.imagePath
                    )
                  }
                />
              </MDBCol>
            </MDBRow>
          ))}




So this collects the data and displays it perfectly. The only problem is that state is not working so the user cannot edit the field. The input value remains the same no matter what the user types.

Please not that the user does not have to input data into every input field. so the formValues variable only holds those they use. Otherwise I would probably just loop over the formValues array. ' Thank you for your help.

2 Answers 2

0

Basic example

import React, { useState, useEffect } from 'react';

const DynamicInputFields = () => {
  const [userData, setUserData] = useState([]);
  const [inputFields, setInputFields] = useState([]);

  useEffect(() => {
    // fetch user data from database
    const fetchUserData = async () => {
      const response = await fetch('your-api-endpoint');
      const data = await response.json();
      setUserData(data);
    };
    fetchUserData();
  }, []);

  useEffect(() => {
    setInputFields(userData.map((item, index) => (
      <div key={index}>
        <input
          type="text"
          value={item.value}
          onChange={(e) => handleInputChange(e, index)}
        />
      </div>
    )));
  }, [userData]);

  const handleInputChange = (e, index) => {
    const updatedData = [...userData];
    updatedData[index].value = e.target.value;
    setUserData(updatedData);
  };

  return (
    <form>
      {inputFields}
      <button type="submit">Submit</button>
    </form>
  );
};

export default DynamicInputFields;
1
  • Thank you for the response. In your example, there is only one array of objects which is userData. I also have another array of objects which is the input fields coming from the database. I need to join these together. So I need to match the userData to the input fields. so lets say there are 10 input fields coming from the database. And on the previous visit the user entered data into 3 of them. This would be the edit page where I need to match the user data to the input fields. The input fields may change which is why they are held in the database and not just static.
    – Good Stuff
    Commented Feb 1, 2023 at 7:50
0

I got this from chat gpt and it is what I was looking for...

import React, { useState } from 'react';

const DynamicForm = ({ formData, userData }) => {
  const [formValues, setFormValues] = useState({});

  const handleInputChange = (event) => {
    setFormValues({
      ...formValues,
      [event.target.name]: event.target.value
    });
  };

  return (
    <form>
      {formData.map((input, index) => {
// this is the part I couldn't figure out how to do
        const inputValue = userData.find((data) => data.name === input.name);
// end part I couldn't figure out
            return (
              <div key={index}>
                <label htmlFor={input.name}>{input.label}</label>
                <input
                  type={input.type}
                  id={input.name}
                  name={input.name}
                  value={inputValue ? inputValue.value : formValues[input.name] || ''}
                  onChange={handleInputChange}
                />
              </div>
            );
          })}
          <button type="submit">Submit</button>
        </form>
      );
    };
    
    export default DynamicForm;
1

Not the answer you're looking for? Browse other questions tagged or ask your own question.