Form Data storing in array format - arrays

I have created a form using reactjs now I want to store each submission in an array format
Eg.
item[0]: name:'name1' mail:'asd#sad'
item[1]: name:'name2' mail:'ds#asd'
I want in that array format and how do I achieve that?
I have tried the below code to store the data in array format but whenever I submit it creates new array everything should be stored in a single element
import React from 'react'
import './style.css'
class FormSample extends React.Component{
constructor(props){
super(props);
this.state={
fname:'',
lname:'',
email:'',
subject:'',
data:[]
}
}
handleFormSubmit(event){
event.preventDefault();
let items = [...this.state.data]
items.push({
fname: this.state.fname,
lname: this.state.lname,
email: this.state.email,
subject: this.state.subject
});
this.setState({
items,
// fname:'',
// lname:'',
// email:'',
// subject:'',
})
console.log(this.state)
}
render(){
return(
<div className="formData">
<p>Contact me</p>
<div>
<form action="#">
<label>first name</label>
<input
type="text"
id="fname"
name="firstname"
placeholder="your name..."
value={this.state.fname}
onChange={e => this.setState({fname: e.target.value})}/>
<label>last name</label>
<input
type="text"
id="lname"
name="lastname"
placeholder="last name.."
value={this.state.lname}
onChange={e => this.setState({lname: e.target.value})}/>
<label>Email</label>
<input
type="email"
id="email"
name="email"
placeholder="email"
value={this.state.email}
onChange={e => this.setState({email: e.target.value})}/>
<label>Subject</label>
<textarea
id="subject"
name="subject"
placeholder="write..."
value={this.state.subject}
onChange={e => this.setState({subject: e.target.value})}/>
<input type="submit" value="submit" onClick={e => this.handleFormSubmit(e)}/>
</form>
</div>
</div>
)
}
}
export default FormSample;
The output I got below in the console
After storing in the array format how do I fetch the data to display in the table format?

When setting state depends on previous state, always use an updater function rather than referring to state values directly.
I.e. don't do:
this.setState({myVal: this.state.myVal + 1})
Instead do:
setState(prevState => {myVal: prevState.myVal + 1})
This is due to the way React batches state updates. You can read more about it in the React docs on setting state.
That means that your code should read something like:
handleFormSubmit(event) {
event.preventDefault()
this.setState(prevState => ({
data: [...prevState.data,
{
fname: prevState.fname,
lname: prevState.lname,
email: prevState.email,
subject: prevState.subject
}]
}))
}
Here we are using the spread operator ... to create a new data array filled with the previous data array's values, and appending a new object to the end of it.
I saw on another answer that someone recommended using 'this.state.data.push({})`.
You should never mutate state directly. Array.prototype.push mutates the current array, meaning this is bad bad bad.
Stick with updating state in the correct way, using immutable objects and creating new arrays rather than pushing to existing ones.
To answer your question on how to access data once it's in the array, you just use standard syntax:
const { fname, lname, email, subject } = this.state.data[i]
where i is the index of the data object you are trying to access. I've used the object destructor syntax above because it exposes object properties nicely.

It Will Help You......
<table>
<tr>
<td>name</td>
<td>mail</td
</tr>
data.map((key,value)=>{
<tr key={key}>
<td>{value.name}</td>
<td>{value.name}</td>
</tr>
});
</table>

Do like this then you can store data in Array:-
handleFormSubmit(event) {
debugger;
event.preventDefault();
this.setState({
data: this.state.data.push({
fname: this.state.fname,
lname: this.state.lname,
email: this.state.email,
subject: this.state.subject
})
});
console.log(this.state);
}
render() {
const list = this.state.data;
return (
<div className="formData">
<p>Contact me</p>
<div>
<form action="#">
<label>first name</label>
<input
type="text"
id="fname"
name="firstname"
placeholder="your name..."
value={this.state.fname}
onChange={e => this.setState({ fname: e.target.value })}
/>
<label>last name</label>
<input
type="text"
id="lname"
name="lastname"
placeholder="last name.."
value={this.state.lname}
onChange={e => this.setState({ lname: e.target.value })}
/>
<label>Email</label>
<input
type="email"
id="email"
name="email"
placeholder="email"
value={this.state.email}
onChange={e => this.setState({ email: e.target.value })}
/>
<label>Subject</label>
<textarea
id="subject"
name="subject"
placeholder="write..."
value={this.state.subject}
onChange={e => this.setState({ subject: e.target.value })}
/>
<input
type="submit"
value="submit"
onClick={e => this.handleFormSubmit(e)}
/>
</form>
</div>
<Table data={this.state.data} />
</div>
);
}
And for displaying data in table :-
class Table extends Component {
state = {
list: this.props.data
};
render() {
return (
<div id="Table">
<table>
<thead>
<tr>
<th>fname</th>
<th>lname</th>
</tr>
</thead>
<tbody>
{this.state.list.map(item => {
return (
<tr>
<td>{item.fname}</td>
<td>{item.lname}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}

Related

setState not working after submit but data is updated in database

I am new to react and Im working on reactjs with laravel api.
I designed a form using reactjs and plan on submitting the data of the form to phpmyadmin database using laravel as the api.
The problem is if I submit the data, I use setState to empty the form data, but it doesnt; but the data gets entered into the phpmyadmin database. I even try to log the response from the api to the console, but there is no message on the console of the browser.
Here is my code on the react end:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
class Addstudent extends Component {
state = {
name: '',
course: '',
email: '',
phone: '',
};
handleInput = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
saveStudent = async (e) => {
e.preventDefault();
const res = await axios.post(
'http://localhost:8000/api/add-student',
this.state
);
if (res.data.status === 200) {
console.log(res.data.message);
this.setState({
name: '',
course: '',
email: '',
phone: '',
});
}
};
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-12">
<div className="card">
<div className="card">
<div className="card-header">
<h4>Add Students</h4>
<Link to={'/'} className="btn btn-primary btn-sm float-end">
Back
</Link>
</div>
<div className="card-body">
<form onSubmit={this.saveStudent}>
<div className="form-group mb-3">
<label>Student Name</label>
<input
type="text"
name="name"
onChange={this.handleInput}
className="form-control"
placeholder="Enter Name"
value={this.state.name}
></input>
</div>
<div className="form-group mb-3">
<label>Student Course</label>
<input
type="text"
name="course"
onChange={this.handleInput}
className="form-control"
placeholder="Enter Course"
value={this.state.course}
></input>
</div>
<div className="form-group mb-3">
<label>Student Email</label>
<input
type="text"
name="email"
onChange={this.handleInput}
className="form-control"
placeholder="Enter Email"
value={this.state.email}
></input>
</div>
<div className="form-group mb-3">
<label>Student Phone</label>
<input
type="text"
name="phone"
onChange={this.handleInput}
className="form-control"
placeholder="Enter Phone"
value={this.state.phone}
></input>
</div>
<div className="form-group mb-3">
<button type="submit" className="btn btn-primary">
Save Student
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Addstudent;
On the Laravel end Here is the code on the controller handling the post request:
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Student;
class StudentController extends Controller
{
public function store(Request $request){
$student = new Student;
$student->name =$request->input('name');
$student->course =$request->input('course');
$student->email =$request->input('email');
$student->phone =$request->input('phone');
$student->save();
return response()->json([
'status'=> '200',
'message'=>'Student Added Successfully',
]);
}
}
Your handleInput function is overwriting your state with only one property, you have to keep the old data:
this.setState(s => ({
...s,
[e.target.name]: e.target.value,
}));
Otherwise you will never send all values to the API, assuming it is working correctly there
if (res.data.status === 200) {
console.log(res.data.message);
This logging is great if everything works well, but you may want to log if things go wrong too, so you could notice that you're not sending all values to the database:
try {
const res = await axios.post(
'http://localhost:8000/api/add-student',
this.state
);
// ... code using res
} catch(e) {
console.error(e);
}

React input box no longer works

I am new to react and when I change my state from just variables to an object the input box no longer works.
The following code works
class AddMovie extends Component {
state = {
title: "",
watched: ""
}
onChangeMovie = (e) => {
this.setState({[e.target.name] : e.target.value});
}
uploadMovie = (e) => {
e.preventDefault();
this.props.addMovie(this.state.title, this.state.watched);
this.setState({title: "", watched: ""})
}
render(){
return (
<form onSubmit={this.uploadMovie}>
<div className="form-group">
<label>Movie Title</label>
<input type="text" className="form-control" placeholder="Enter title"
name="title" value={this.state.title} onChange={this.onChangeMovie}/>
</div>
<div className="form-group">
<label>Date Watched</label>
<input type="date" className="form-control"
name="watched" value={this.state.watched} onChange={this.onChangeMovie}/>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
)
}
}
export default AddMovie;
When I change the state to an object
state ={
movieUpload: {
title: "",
watched: ""
}
}
and I change the form to add the object
render(){
return (
<form onSubmit={this.uploadMovie}>
<div className="form-group">
<label>Movie Title</label>
<input type="text" className="form-control" placeholder="Enter title"
name="title" value={this.state.movieUpload.title} onChange={this.onChangeMovie}/>
</div>
<div className="form-group">
<label>Date Watched</label>
<input type="date" className="form-control"
name="watched" value={this.state.movieUpload.watched} onChange={this.onChangeMovie}/>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
)
}
The input box no longer works. Why is this and how do I change it?
If you're going to make those changes, you need to change your onChangeMovie as well
onChangeMovie = (e) => {
this.setState({uploadMovie: {...this.state.uploadMovie, [e.target.name] : e.target.value}});
}
This will copy the current this.state.uploadMovie and then overwrite the title/watched.

React clear input field after submit form

I want to clear the input field after upload and submit the form.
I have checked couple of documentation, where its said after submitting the form I can return the initial state.
Here is my code
state = {
firstname: "",
lastname: "",
email: "",
file: null
};
onDrop = e => {
this.setState({ file: e.target.files[0] });
console.log({ file: e.target.files[0] });
};
handleChange = e => {
this.setState({ [e.target.id]: e.target.value });
};
handleSubmit = async e => {
e.preventDefault();
console.log(this.state);
const formData = new FormData();
formData.append("file", this.state.file);
formData.append("upload_preset", process.env.REACT_APP_UPLOAD_PRESET);
const response = await axios.post(
`https://api.cloudinary.com/v1_1/${process.env.REACT_APP_CLOUD_NAME}/image/upload`,
formData
);
await this.props.addPerson({
variables: {
firstname: this.state.firstname,
lastname: this.state.lastname,
email: this.state.email,
image: response.data.url
},
refetchQueries: [{ query: getperson }]
});
this.setState({ firstname: " ", lastname: "", email: " ", file: null }); **this is where i retutn the initial state after submitting the form, but it did not work**
};
This is my form setup
<React.Fragment>
<div>
<form id="addPerson" onSubmit={this.handleSubmit}>
<div className="field">
<label> Firstname </label>
<input type="text" id="firstname" onChange={this.handleChange} />
</div>
<div className="field">
<label> Lastname </label>
<input type="text" id="lastname" onChange={this.handleChange} />
</div>
<div className="field">
<label> Email </label>
<input type="email" id="email" onChange={this.handleChange} />
</div>
<input type="file" onChange={this.onDrop} />
<button>Add Person</button>
</form>
</div>
</React.Fragment>
It doesn't work because your inputs are not fully controlled by react, If you want to control these inputs, you need to specify the value attribute like this :
<input type="text" id="firstname" value={this.state.firstname} onChange={this.handleChange}/>
<input type="text" id="lastname" value={this.state.lastname} onChange={this.handleChange}/>
Note that the file input is always uncontrolled in react (see the documentation), so you need to reset it manually by using a reference :
constructor() {
this.fileRef = React.createRef();
...
}
handleSubmit = async e => {
// Reset the file input
this.fileRef.current.value = '';
};
render() {
...
<input type="file" ref={this.fileRef} onChange={this.onDrop} />
...
}
You haven't set the value attribute in html input with state value.
Since the value attribute is set on our form element, the displayed value will always be this.state.value, making the React state the source of truth.
Since handleChange runs on every keystroke to update the React state, the displayed value will update as the user types.
With a controlled component, every state mutation will have an associated handler function. This makes it straightforward to modify or validate user input.
For more details please check here.
Use following code,
<React.Fragment>
<div>
<form id="addPerson" onSubmit={this.handleSubmit}>
<div className="field">
<label> Firstname </label>
<input type="text" id="firstname" value={this.state.firstname} onChange={this.handleChange} />
</div>
<div className="field">
<label> Lastname </label>
<input type="text" id="lastname" value={this.state.lastname} onChange={this.handleChange} />
</div>
<div className="field">
<label> Email </label>
<input type="email" id="email" value={this.state.email} onChange={this.handleChange} />
</div>
<input type="file" onChange={this.onDrop} />
<button>Add Person</button>
</form>
</div>
</React.Fragment>
Hope this will help you !!!

Edit and Delete functionality is not working as Excepted

I Have a form,when I submit the details of that form,It will redirect to next page and date will display there. There itself I have two buttons to Edit and Delete.That two Functionality is not working..
Can you help me in this?? Thanks in Advance..
import React, { Component } from 'react';
import axios from "axios";
import {withRouter} from 'react-router';
class App extends Component {
constructor(props) {
super(props)
this.state = {
data:[],
objEdit:obj
}
}
// handleInput(e){
// this.state.objEdit[e.target.name] = e.target.value
// this.setState({objEdit:this.state.objEdit})
// }
handleInput(e){
this.setState({
objEdit:{...this.state.objEdit, [e.target.name] : e.target.value}
})
}
updateUser = () =>{
console.log(this.state.objEdit)
const objEdit = {...this.state.objEdit, id: null};
axios.post("http://localhost:3000/data/", objEdit).then(()=>{
this.props.history.push('/Form')
}).catch((error)=>{
console.log("Error Occured")
})
}
render() {
return (
<div>
<div className="col-sm-4">
<form>
<div className="form-group">
<label htmlFor="fname">First Name</label>
<input type="text" className="form-control" name="fname" placeholder="Enter First Name" value={this.state.objEdit.fname} onChange={(e)=>{this.handleInput(e)}}/>
</div>
<div className="form-group">
<label htmlFor="lname">Last Name</label>
<input type="text" className="form-control" name="lname" placeholder="Enter First Name" value={this.state.objEdit.lname} onChange={(e)=>{this.handleInput(e)}}/>
</div>
<div className="form-group">
<label htmlFor="tel">Tel</label>
<input type="text" className="form-control" name="tel" placeholder="Tel" value={this.state.objEdit.tel} onChange={(e)=>{this.handleInput(e)}}/>
</div>
<div className="form-group">
<label htmlFor="address">Address</label>
<input type="text" className="form-control" name="address" placeholder="Enter First Name" value={this.state.objEdit.address} onChange={(e)=>{this.handleInput(e)}}/>
</div>
<div className="form-group">
<label htmlFor="fname">City</label>
<input type="text" className="form-control" name="city" placeholder="Enter First Name" value={this.state.objEdit.city} onChange={(e)=>{this.handleInput(e)}}/>
</div>
<div className="form-group">
<label htmlFor="state">State</label>
<input type="text" className="form-control" name="state" placeholder="Enter First Name" value={this.state.objEdit.state} onChange={(e)=>{this.handleInput(e)}}/>
</div>
<div className="form-group">
<label htmlFor="zip">Zip</label>
<input type="text" className="form-control" name="zip" placeholder="Enter First Name" value={this.state.objEdit.zip} onChange={(e)=>{this.handleInput(e)}}/>
</div>
<button type="button" className="btn btn-primary" onClick={this.updateUser}>Submit</button>
</form>
</div>
</div>
// </div>
)
}
}
export default withRouter(App);
Here my Edit and Delete Function are there.I have two buttons to Edit and Delete.That two Functionality is not working..
let obj={
fname:"",
lname:"",
tel:"",
address:"",
city:"",
state:"",
zip:'',
id:''
}
import React, { Component } from 'react'
import axios from "axios";
import { Link } from 'react-router-dom';
class Form extends Component {
constructor(props) {
super(props)
this.state = {
data:[],
}
}
componentDidMount(){
fetch('http://localhost:3000/data')
.then(response => response.json())
.then(user => this.setState({data:user}))
}
editUser=(obj,index)=>{
console.log(obj,index)
this.setState({objEdit:obj})
}
deleteUser=(i)=>{
console.log("deleteUser called",i)
axios.delete("http://localhost:3000/data/"+this.state.data[i].id).then(res=>{
console.log()
}).catch((error)=>{
console.log("Error Occured")
})
}
render() {
return (
<div>
<div className="row">
<div className="col-sm-8">
<table className="table">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Tel</th>
<th>Address</th>
<th>City</th>
<th>State</th>
<th>Zip</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{this.state.data.map((obj,i)=>{
return <tr key={i}>{Object.keys(obj).map((property)=>{
return <td key={property}>{obj[property]}</td>
})}<td><button onClick={()=>{this.editUser(obj,i)}} className="btn btn-info">Edit</button></td>
<td><button onClick={()=>{this.deleteUser(i)}} className="btn btn-danger">Delete</button></td></tr>
})}
</tbody>
<Link to ="/"> <button type="button" className="btn btn-primary" >Back</button></Link>
</table>
</div>
</div>
</div>
)
}
}
export default Form;
Delete is a simple. As you are iterating over local state for your data, you need to delete the data from local state when you get success from delete axios call,
deleteUser=(i)=>{
console.log("deleteUser called",i)
axios.delete("http://localhost:3000/data/"+this.state.data[i].id).then(res=>{
console.log("success");
this.state.data.splice(i,1); //This will delete data fro local state.
}).catch((error)=>{
console.log("Error Occured")
})
}
Now for update you cannot directly setState state from some other component where you don't have any relation.
this.setState({objEdit:obj})
This cannot be done, because objEdit is from App component. You don't have any relation between App and Form component.
One way is you can pass obj like, (Just an idea)
editUser=(obj,index)=>{
console.log(obj,index)
this.props.history.push({
pathname:"/", //probablt this is for App component
state: {objEdit : JSON.stringify(obj)}
})
}
Of course you need to wrap Form component using withRouter,
export default withRouter(Form)
Now in App component you can get this data in componentDiMount,
componentDidMount(){
let objEdit = JSON.parse(this.props.location.state.objEdit)
if(objEdit){
this.setState({objEdit})
}
}
Now you will get pre-filled values in your form, you just need to handle the update button functionality.
In your update function you are adding id manually,
const objEdit = {...this.state.objEdit, id: null};
But in this case you need to have check that if objEdit alreay have id, if yes then you need to hit the update API call.

Mapping objects in an array to table in React

Could you please help me in passing objects in a state array to the table using map method in react?
I can able to push the object into the invoices array but I can't map into the table.
Please suggest if any other method is possible.
Please neglect the below comments as I am going repeat the above context.
Could you please help me in passing objects in a state array to the table using map method in react?
I can able to push the object into the invoices array but I can't map into the table.
Please suggest if any other method is possible.
import React, { Component } from 'react';
class Form extends Component {
constructor(props) {
super(props);
this.state = {
company: "",
address: "",
zip: "",
date: "",
description: "",
unit: "",
quantity: "",
invoices: []
};
}
handleChange = (e) => {
e.preventDefault();
this.setState({ [e.target.name]: e.target.value })
};
handleSubmit = (e) => {
e.preventDefault();
this.state.invoices.push({
description: this.state.description,
unit: this.state.unit,
quantity: this.state.quantity
});
//console.log(this.state.invoices[].description);
};
render() {
const hrStyle = {
border: '5px solid rgb(23, 162, 184)'
};
const list = this.state.invoices.map((invoice, index) => {
return (
<tr key={index}>
<td>{invoice[index].description}</td>
<td>{invoice[index].unit}</td>
<td>{invoice[index].quantity}</td>
<td>{invoice[index].unit * invoice[index].quantity}</td>
</tr>
)
});
return (
<React.Fragment>
<div className='col-12 col-lg-6'>
<div className="jumbotron">
<form>
<label><h4>Billed To: </h4></label><br />
<div className="form-group">
<label>Company Name</label>
<input onChange={this.handleChange} className="form-control" type="text" name="company" />
</div>
<div className="form-group">
<label>Address</label>
<input className="form-control" type="text" onChange={this.handleChange} name="address" />
<label>Zip Code</label>
<input className="form-control" type="number" onChange={this.handleChange} name="zip" /></div>
<div className="form-group">
<label>Date</label>
<input className="form-control" type="date" onChange={this.handleChange} name="date" />
</div>
</form>
<form onSubmit={this.handleSubmit}>
<label><h4>Invoice: </h4></label><br />
<div className="form-group">
<label>Description</label>
<input className="form-control" type="text" onChange={this.handleChange} name="description" />
</div>
<div className="form-group">
<label>Unit Price</label>
<input className="form-control" type="number" onChange={this.handleChange} name="unit" />
<label>Quantity</label>
<input className="form-control" type="number" onChange={this.handleChange} name="quantity" />
</div>
<button className="btn btn-primary btn-sm">Add Invoices</button>
</form>
</div>
</div>
<div className="col-12 col-lg-6">
<div className="container-fluid bg-info text-white">
<div className="row">
<div className="col text-left">
<p>Your Company Name</p>
<h2>Invoice</h2>
</div>
<div className="col text-right">
<p>22 Yusen St</p><br />
<p>Auburn</p><br />
<p>NSW</p>
</div>
</div>
</div>
<div className="container-fluid">
<div className="row">
<div className="col-4">
<p>{this.state.company}</p>
<p>{this.state.address}</p>
<p>{this.state.Zip}</p>
</div>
<div className="col-4">
<div>
<h5>Invoive number</h5>
<p>{Math.floor((Math.random() * 100) + 1)}</p>
</div>
<div>
<h5>Date</h5>
<p>{this.state.date}</p>
</div>
</div>
<div className="col-4">
<div>
<h5>Invoice Totals</h5>
<p>$2587.35</p>
</div>
</div>
</div>
</div>
<hr style={hrStyle} />
<div className="Invoices">
<table className="table">
<thead>
<tr>
<th>Description</th>
<th>Unit Price</th>
<th>Quantity</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{list}
</tbody>
</table>
</div>
</div>
</React.Fragment>
);
}
}
export default Form;
One possible issue that I can see is not properly setting state in handleSubmit. You should do something like this:
handleSubmit = (e) => {
e.preventDefault();
const copyStateInvoices = [...this.state.invoices]
copyStateInvoices.push({
description: this.state.description,
unit: this.state.unit,
quantity: this.state.quantity
})
this.setState({
invoices: copyStateInvoices,
})
//console.log(this.state.invoices[].description);
};
Component's state is immutable and if you try to change the values in state it will happen but react will not respect that. Read more about these fundamentals on react main website.
Thanks
Try with following changes.
Needs change in pushing objects to an array state
To push objects or values or numbers in react you should do something like below. The recommended approach to push values to an array in React is using prevState
handleSubmit = (e) => {
e.preventDefault();
this.setState(prevState => ({
invoices: [...prevState.invoices, {
description: this.state.description,
unit: this.state.unit,
quantity: this.state.quantity
}]
}));
};
And in .map you no need to do invoice[index] to get the value because you are doing .map on array so it gives you each object in loop so you can directly access invoice.unit directly and invoice[index].unit is not needed and not correct in loop
const list = this.state.invoices.map((invoice, index) => {
return (
<tr key={index}>
<td>{invoice.description}</td>
<td>{invoice.unit}</td>
<td>{invoice.quantity}</td>
<td>{invoice.unit * invoice.quantity}</td>
</tr>
)
});

Resources