0

I've been trying to create a form that can add a list of objects with multiple attributes to a list. I managed to get this right with one string attribute. But, I cannot figure out how to add an entire object with property values passed from the form. I'm using functional components to do this........How can I create a form that adds new objects of items to a list? I'm fairly new to ReactJS, btw.

resume.jsx

  function App() {
    const [jobExperience, setjobExperience] = useState([{
     jobCompanyName: '',
     jobDateRangeStart: '',
     jobDateRangeEnd: '',
     jobDescription: '',
     reference_up_count: 0,
     reference_down_count: 0,
    }]);
    
       const refUpvoteCount = index => {
            const newReferences = [...jobExperience];
            newReferences[index].reference_upvote_count++;
            setjobExperience(newReferences)
        }
    
        const refDownvoteCount = index => {
            const newReferences = [...jobExperience];
            newReferences[index].reference_downvote_count++;
            setjobExperience(newReferences)
        }
    
    return(
     <Container className="container-fluid g-0">
      <Row>
        <Col>
          <div>
             {jobExperience.map((jobExp, index) => (
                         <JobExperience key={index} jobExperience={jobExp} refUpvote={refUpvoteCount} refDownvote={refDownvoteCount}
                   ))}
          </div>
        </Col>
    <Col>
     <div className="pl-5 pr-5 pb-2">
<form onSubmit={//Add To Array of item Objects}>
                                    <div className="form-group">
                                        <label>Company Name</label>
                                        <input type="text" className="form-control" placeholder="Add Company Name" name="jobCompanyName" onChange={handleJobExperienceChange}  />
                                    </div>
                                  <div className="form-row">
                                      <div className="col">
                                          <div className="form-group">
                                              <label>Start Date</label>
                                              <Datetime dateFormat="YYYY" timeFormat={false} onChange={(date) => setstartDate(date.year())} value={jobExperience.jobDateRangeStart} />
                                          </div>
                                      </div>
                                      <div className="col">
                                          <div className="form-group">
                                              <label>End Date</label>
                                              <Datetime dateFormat="YYYY" name="jobDateRangeEnd" timeFormat={false} onChange={(date) => setendDate(date.year())} value={jobExperience.jobDateRangeEnd} />
                                          </div>
                                      </div>
                                  </div>
                                    <div className="pt-1">
                                        <div className="form-group">
                                            <label>Job Role/Responsibilities</label>
                                            <textarea style={{width: '100%'}} name="jobDescription" onChange={handleJobExperienceChange} />
                                            <button type="submit" onClick={handleJobExperienceAdd} className="btn btn-success btn-sm btn-block">Add Job Experience</button>
                                        </div>
                                    </div>
    
                                </div>
</form>
    </Col>
      </Row>
    </Container>
    )
    }
    
    
    function JobExperience({jobExperience, index, refUpvote, refDownvote}) {
        return (
            <div>
                <Card style={{width: '18rem'}} className="remove-border-radius">
                    <Card.Body>
                        <Card.Title><span><i className="fa fa-building"></i> {jobExperience.jobCompanyName}</span></Card.Title>
                    </Card.Body>
                    <Card.Text>
                       <i className="fa fa-calendar"></i> {jobExperience.jobDateRangeStart}-{jobExperience.jobDateRangeEnd}
                    </Card.Text>
                    <Card.Text>
                       <span><i className="fa fa-info-circle"></i> {jobExperience.jobDescription}</span>
                    </Card.Text>
                    <Button variant="primary" onClick={() => refUpvote(index)} className="remove-border-radius"><i className="fa fa-plus"></i> Reference {jobExperience.reference_upvote_count}</Button>
                    <Button variant="danger" onClick={() => refDownvote(index)} className="remove-border-radius"><i className="fa fa-minus-circle"></i> Reference {jobExperience.reference_downvote_count}</Button>
                </Card>
            </div>
    
        )
    }
3
  • Where is the form and what object and attributes are you trying to add/update? Commented Sep 27, 2020 at 18:30
  • I'm not trying to update the values. I'm trying to add multiple job experiences to a list in the view. I did it without issue, using the task manager approach. I just didn't know how to use more than one attribute for it. Someone suggested that I use a form for this particular task. Commented Sep 27, 2020 at 19:37
  • I guess the question is more, where is the code for where you are trying to add attributes. I don't see a form and I don't see where anything is attempted to be added to some state. Commented Sep 27, 2020 at 19:42

3 Answers 3

1

Change the way you set your state from this:

const refUpvoteCount = (index) => {
  const newReferences = [...jobExperience];
  newReferences[index].reference_upvote_count++;
  setjobExperience(newReferences);
};

const refDownvoteCount = (index) => {
  const newReferences = [...jobExperience];
  newReferences[index].reference_downvote_count++;
  setjobExperience(newReferences);
};

To this:

const refUpvoteCount = (index) => {
  setjobExperience((previousState) => {
    const newReferences = [...previousState];
    newReferences[index].reference_upvote_count++;
    return newReferences;
  });
}

const refDownvoteCount = (index) => {
  setjobExperience((previousState) => {
    const newReferences = [...previousState];
    newReferences[index].reference_downvote_count++;
    return newReferences;
  });
}

You may also take note the difference to understand this other way of setting-up state that needs to have the the value of the previous state

Do it like this.

const myFunction = () => {
  setState((previousState)=> newState)
}

If you need to get the reference of the previous state pass a callback function on setState and that call back function can take 1 parameter which that represent the previous state. And on the callback function you can do some operations if you need to. The return value of callback function will be the new state

And not like this

const myFunction = () => {
  const newState = state
  setState(newState)
}

This last code sample reference the previous state the wrong way and will not work

Sign up to request clarification or add additional context in comments.

Comments

0
const [form, setForm] = useState({}); // form is the previous jobExperience object

const onChange = (event) => {
  const { name, value } = event.target;
  let savedValue = value;

  /* 
     condition your changes below, you can also extract 
     the content of the condition to separate functions
  */
  if (name === 'jobDateRangeStart') {
    savedValue = []; // whatever you need to do with the value
  }

  if (name === 'jobDateRangeEnd') {
    savedValue = []; // whatever you need to do with the value
  }

  if (name === 'jobDateRangeEnd') {
    savedValue = []; // whatever you need to do with the value
  }
    
  setForm({ ...form, [name]: savedValue });
};


return (
  <div className="pl-5 pr-5 pb-2">
    <div className="form-group">
      <label>Company Name</label>
      <input
        className="form-control"
        name="jobCompanyName"
        onChange={handleChange}
        placeholder="Add Company Name"
        type="text"
        value={form.jobCompanyName || ''}
      />
    </div>
    <div className="form-row">
      <div className="col">
        <div className="form-group">
          <label>Start Date</label>
          <Datetime
            dateFormat="YYYY"
            onChange={handleChange}
            timeFormat={false}
            value={form.jobDateRangeStart || ''}
          />
        </div>
      </div>
      <div className="col">
        <div className="form-group">
          <label>End Date</label>
          <Datetime
            dateFormat="YYYY"
            name="jobDateRangeEnd"
            onChange={handleChange}
            timeFormat={false}
            value={form.jobDateRangeEnd || ''}
          />
        </div>
      </div>
    </div>
    <div className="pt-1">
      <div className="form-group">
        <label>Job Role/Responsibilities</label>
        <textarea
          name="jobDescription"
          onChange={handleChange}
          value={form.jobDescription || ''}
          style={{width: '100%'}}
        />
        <button
          className="btn btn-success btn-sm btn-block"
          onClick={handleChange}
          type="submit"
        >
          Add Job Experience
        </button>
      </div>
    </div>
  </div>
);

Comments

0

As far as i understood you are trying to add an object into an array with multiple fields . and the value of object will come from the values of your form . Here's how can you do it.

# Step 1 :

first create a state that will hold the array of objects .

const [arrayOfObjects , setArrayOfObjects ] = useState([]) ;  // empty array initially

# Step 2 :

grab the value from your form's submit function and create the object

onSubmitHandler = () => {
   
   const newObject = {
      property1 : "some value "  // this values will come from your form
      property2 : "some value "  // depending on your implementation you may have to maintain separate state for each property
   }

   const newState = [ ...arrayOfObjects , newObject ];
   
   setArrayOfObjects(newState);

}

1 Comment

array::push returns the new length of the array, this solution won't work.

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.