Mapping objects in an array to table in React - arrays

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>
)
});

Related

How to fix error "Warning: A component is changing a controlled input to be uncontrolled"

I'm getting this error below. Where in my code is the problem? The solutions I saw on google or stackoverflow hasn't helped so far.
Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
There are 2 files most of my customer code is on. ContactForm.js & Contact.js
The tutorial I'm stuck in is this. At 37:27, we see the edit icon clicked and it populates the fields & that's not happening for me.
The source code is here.
ContactForm.js
import React, { useState, useEffect } from "react";
const ContactForm = (props) => {
const initialFieldValues = {
fullName: "",
mobile: "",
email: "",
address: ""
}
var [values, setValues] = useState(initialFieldValues)
useEffect(() => {
if (props.currentId == "")
setValues({ ...initialFieldValues })
else
setValues({
...props.contactObjects[props.currentId]
})
}, [props.currentId, props.contactObjects])
const handleInputChange = e => {
var { name, value } = e.target;
setValues({
...values,
[name]: value
})
}
const handleFormSubmit = e => {
e.preventDefault();
props.addOrEdit(values)
}
return (
<form autoComplete="off" onSubmit={handleFormSubmit}>
<div className="form-row">
<div className="form-group input-group">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-user"></i>
</div>
</div>
<input className="form-control" name="fullName" placeholder="Full Name"
value={values.fullName}
onChange={handleInputChange}
/>
</div>
<div className="form-group input-group col-md-6">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-mobile-alt"></i>
</div>
</div>
<input className="form-control" name="mobile" placeholder="Mobile"
value={values.mobile}
onChange={handleInputChange}
/>
</div>
<div className="form-group input-group col-md-6">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-envelope"></i>
</div>
</div>
<input className="form-control" name="email" placeholder="Email"
value={values.email}
onChange={handleInputChange}
/>
</div>
</div>
<div className="form-group">
<textarea className="form-control" name="address" placeholder="Address"
value={values.address}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<input type="submit" value="Save" className="btn btn-primary btn-block" />
</div>
</form>
);
}
export default ContactForm;
Contacts.js
import React, { useState, useEffect } from "react";
import ContactForm from "./ContactForm"
import firebaseDb from "../firebase";
const Contacts = () => {
var [contactObjects, setContactObjects] = useState({})
var [currentId, setCurrentId] = useState("")
//Once components load complete
useEffect(() => {
firebaseDb.child("contacts").on("value", snapshot => {
if (snapshot.val() != null) {
setContactObjects({
...snapshot.val()
});
}
})
}, []) // Similar to componentDidMount
const addOrEdit = (obj) => {
firebaseDb.child('contacts').push(
obj,
err => {
if (err)
console.log(err)
})
}
return (
<>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4 text-center">Contact Register</h1>
</div>
</div>
<div className="row">
<div className="col-md-5">
<ContactForm {...({ currentId, contactObjects, addOrEdit })} ></ContactForm>
</div>
<div className="col-md-7">
<div>
<table className="table table-borderless table-stripped">
<thead className="thead-light">
<tr>
<th>Full Name</th>
<th>Mobile</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{
Object.keys(contactObjects).map(id => {
return <tr key={id}>
<td>{contactObjects[id].fullName}</td>
<td>{contactObjects[id].mobile}</td>
<td>{contactObjects[id].email}</td>
<td className="bg-light">
<a className="btn text-primary" onClick={() => { setCurrentId() }}>
<i className="fas fa-pencil-alt"></i>
</a>
<a className="btn text-danger" >
<i className="far fa-trash-alt"></i>
</a>
</td>
</tr>
})
}
</tbody>
</table>
</div>
</div>
</div>
</>
);
}
export default Contacts;
Hell. I think the problems arises when you call setCurrentId function in the Contacts.js file.
No parameter is given, which means currentId is interpreted as undefined.
You can update ContactForm as below.
...
useEffect(() => {
if (!props.currentId)
setValues({ ...initialFieldValues })
...

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. Error in Contact.js file

I am trying to get my form populated when I click on the edit pencil button but I keep getting the error 'to many re-renders'. Anyone can help here? down below my two files
I am using firebase to pull out data from a collection and basically I am trying to build a simple application where you can display data from that database and then eventually edit it or delete it
Contact.js
import React, { useState, useEffect } from "react";
import ContactForm from "./ContactForm";
import firebaseDb from "../firebase";
const Contacts = () => {
var [learnerObjects, setLearnerObjects] = useState({});
var [currentId, setCurrentId] = useState("");
useEffect(() => {
firebaseDb.child("learners").on("value", (snapshot) => {
if (snapshot.val() != null)
setLearnerObjects({
...snapshot.val(),
});
});
}, []);
const addOrEdit = (obj) => {
firebaseDb.child("learners").push(obj, (err) => {
if (err) console.log(err);
});
};
return (
<>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4 text-center">Contact Register</h1>
</div>
</div>
<div className="row">
<div className="col-md-5">
<ContactForm
{...setCurrentId({ addOrEdit, currentId, learnerObjects })}
/>
</div>
<div className="col-md-7">
<table className="table table-borderless table-stripped">
<thead className="thead-light">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>email</th>
<th>score</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{Object.keys(learnerObjects).map(id => {
return (
<tr key={id}>
<td>{learnerObjects[id].firstName}</td>
<td>{learnerObjects[id].lastName}</td>
<td>{learnerObjects[id].email}</td>
<td>{learnerObjects[id].score}</td>
<td>
<a
className="btn text-primary"
onClick={() => {
setCurrentId(id)
}}
>
<i className="fas fa-pencil-alt"></i>
</a>
<a className="btn text-danger">
<i className="fas fa-trash-alt"></i>
</a>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</>
);
};
export default Contacts;
ContactForm.js
import React, { useEffect, useState } from "react";
const ContactForm = (props) => {
const initialFieldValues = {
firstName: "",
lastName: "",
email: "",
score: 0,
};
var [values, setValues] = useState(initialFieldValues);
useEffect(() => {
if (props.currentId === '')
setValues({
...initialFieldValues,
});
else
setValues({
...props.learnerObjects[props.currentId],
});
}, [props.currentId, props.learnerObjects]);
const handleInputChange = (e) => {
var { name, value } = e.target;
setValues({
...values,
[name]: value,
});
};
const handleFormSubmit = (e) => {
e.preventDefault();
props.addOrEdit(values);
};
return (
<form autoComplete="off" onSubmit={handleFormSubmit}>
<div className="form-group input-group">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-user"></i>
</div>
</div>
<input
className="form-control"
placeholder="first name"
name="firstName"
value={values.firstName}
onChange={handleInputChange}
/>
</div>
<div className="form-row">
<div className="form-group input-group col-md-6">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-user"></i>
</div>
</div>
<input
className="form-control"
placeholder="last name"
name="lastName"
value={values.lastName}
onChange={handleInputChange}
/>
</div>
<div className="form-group input-group col-md-6">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-user"></i>
</div>
</div>
<input
className="form-control"
placeholder="email"
name="email"
value={values.email}
onChange={handleInputChange}
/>
</div>
</div>
<div className="form-group">
<textarea
className="form-control"
placeholder="score"
name="score"
value={values.score}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<input
type="submit"
value="Save"
className="btn btn-primary btn-block"
/>
</div>
</form>
);
};
export default ContactForm;
You are calling {...setCurrentId({ addOrEdit, currentId, learnerObjects })} on render.
You are updating the useState hook on render, which results in a rerender during which you are again updating the hook resulting in an infinity loop.
You need to update the state somewhere that is not executed on every render.

How to create nested array in object when I use Formik.js?

I want to create a nested board in the facility. Something like this:
I wonder if it is possible to convert everything so that it creates an object from an array unless someone knows a better way or idea for it?
JSON example:
{
"userId": "4",
"offers":[
{
"mallCodename": "gallery",
"shopCodename":"borubar",
"productCodename": "green_socks",
"discount": 30,
"ttl": 3600
},
{
"mallCodename": "gallery",
"shopCodename":"nike",
"productCodename": "sport_shoes",
"discount": 30,
"ttl": 222
}
]
}
This is my component:
export default function Form(props) {
const [values, setInputValue] = useState([]);
const dispatch = useDispatch();
function onChange(e) {
e.preventDefault();
const { name, value, type } = e.target;
setInputValue({ ...values, [name]: value});
}
function onSubmit(e) {
e.preventDefault();
dispatch(sendOffer([values]));
setInputValue([]);
}
return (
<div id="accordion" role="tablist">
<div className="card">
<div className="card-header" role="tab" id="headingOne">
<h5 className="mb-0">
<a
data-toggle="collapse"
href="#collapseOne"
aria-expanded="true"
aria-controls="collapseOne"
>
Rozwin
</a>
</h5>
</div>
<div
id="collapseOne"
className="collapse show"
role="tabpanel"
aria-labelledby="headingOne"
>
<form onSubmit={onSubmit}>
<table className="table table-responsive">
<tbody className="tbody-form-promo">
<tr className="tr-table-form-promo">
<td>Uzytkownik:</td>
<td>Nazwa produktu</td>
<td>Galleria</td>
<td>Nazwa sklepu</td>
<td>Znizka</td>
<td>Czas oferty</td>
</tr>
<tr className="tr-table-form-promo">
<td>{(values.userId = props.userId)}</td>
<td>
<input
className="text-place-post-form"
name="productCodename"
type="text"
placeholder="Nazwa produktu"
value={values.productCodename || ""}
onChange={onChange}
required
/>
</td>
<td>
<input
className="text-place-post-form"
name="mallCodename"
type="text"
placeholder="Galeria"
value={values.mallCodename || ""}
onChange={onChange}
required
/>
</td>
<td>
<input
className="text-place-post-form"
name="shopCodename"
type="text"
placeholder="Nazwa sklepu"
value={values.shopCodename || ""}
onChange={onChange}
required
/>
</td>
<td>
<input
className="text-place-post-form"
name="discount"
type="number"
placeholder="max 100%"
value={values.discount || ""}
onChange={onChange}
onInput={inputMaxLength}
maxLength="3"
max={100}
min={0}
step={1}
required
/>
</td>
<td>
<input
className="text-place-post-form"
type="number"
name="ttl"
placeholder="Max 180 minut"
value={values.ttl || ""}
max={180}
min={0}
step={1}
onChange={onChange}
maxLength="3"
onInput={inputMaxLength}
required
/>
</td>
</tr>
</tbody>
</table>
<div className="container">
<div className="row">
<div className="col-6 col-form-promo">
<Link to="/">
<button
className="btn btn-form-promo"
onClick={props.close}
>
Anuluj
</button>
</Link>
</div>
<div className="col-6 col-form-promo">
<button
className="btn btn-form-promo"
onSubmit={onSubmit}
>
Zapisz
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
I don't have Idee how to convert this. Or If somebody have better ideaa how can I do this. Please tell me :-).Nested array in object is very com
You should use FieldArray.
<FieldArray /> is a component that helps with common array/list manipulations. You pass it a name property with the path to the key within values that holds the relevant array. will then give you access to array helper methods via render props. For convenience, calling these methods will trigger validation and also manage touched for you.
You can also see an example of the exact same situation you have, array with objects inside.

Showing input value in the url link (ReactJs Laravel)

I created laravel project with the reactjs framework and I'm new for this framework. I have problem and why It happens every time i submit the form.
Goal: users can register through online
Problem:
Why it happens when i submit the button the input value of user shown in the url link?
The data that I input is not inserted to the database.
Code:
constructor() {
super();
this.state = {
f_name:'',
l_name:'',
m_name:'',
email:'',
home_num:'',
contact_num:'',
Job_name:[],
employ_status:'',
employ_relocate:'',
employ_start_date:'',
employ_file:''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handle_fname = this.handle_fname.bind(this);
this.handle_lname = this.handle_lname.bind(this);
this.handle_mname = this.handle_mname.bind(this);
this.handle_email = this.handle_email.bind(this);
this.handle_homenum = this.handle_homenum.bind(this);
this.handle_contactnum = this.handle_contactnum.bind(this);
this.handle_employ_status = this.handle_employ_status.bind(this);
this.handle_employ_relocate = this.handle_employ_relocate.bind(this);
this.handle_employ_start_date = this.handle_employ_start_date.bind(this);
this.handle_employ_file = this.handle_employ_file.bind(this);
}
componentDidMount() {
const id = this.props.match.params.id;
axios.get('/api/online_application_job_title/' +id).then(response => {
this.setState({
Job_name:response.data
})
})
}
handleSubmit(e)
{
const data = {
firstname: this.state.f_name,
lastname : this.state.l_name,
middlename : this.state.m_name,
email : this.state.email,
home_number : this.state.home_num,
contact_num : this.state.contact_num,
job : this.state.Job_name[0].position_name,
employ_status : this.state.employ_status,
employ_relocate : this.state.employ_relocate,
employ_start_date : this.state.employ_start_date,
employ_file : this.state.employ_file
}
axios.post('/api/save_application',data).then(response => {
console.log(response);
}).catch(error => console.log(error));
}
handle_fname(e)
{
this.setState({
f_name:e.target.value,
})
}
handle_lname(e){
this.setState({
l_name:e.target.value,
})
}
handle_mname(e){
this.setState({
m_name:e.target.value,
})
}
handle_email(e){
this.setState({
email:e.target.value,
})
}
handle_homenum(e){
this.setState({
home_num:e.target.value
})
}
handle_contactnum(e){
this.setState({
contact_num:e.target.value
})
}
handle_employ_status(e){
this.setState({
employ_status:e.target.value
});
}
handle_employ_relocate(e){
this.setState({
employ_relocate:e.target.value,
})
}
handle_employ_start_date(e){
this.setState({
employ_start_date:e.target.value,
})
}
handle_employ_file(e){
this.setState({
employ_file: e.target.files[0].extension
})
}
renderName() {
return (
this.state.Job_name.map(name => (
<input placeholder="" value={name.position_name} type="text" className="form-control"/>
))
)
}
render() {
return (
<div>
<div className="header">
<div className="jumbotron">
<h1>Online Application</h1>
</div>
</div>
<form onSubmit={this.handleSubmit}>
<div className="container">
<h5><b>Personal Info</b></h5>
<br/>
<div className="row">
<div className="col-md-6">
<input
placeholder="First Name*"
value={this.state.f_name}
onChange={this.handle_fname}
className="form-control"/>
</div>
<div className="col-md-6">
<input
placeholder="Last Name*"
value={this.state.l_name}
onChange={this.handle_lname}
className="form-control"/>
</div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<input
placeholder="Middle Name*"
value={this.state.m_name}
onChange={this.handle_mname}
className="form-control"/>
</div>
<div className="col-md-6">
<input
placeholder="Email Address*"
type="email"
value={this.state.email}
onChange={this.handle_email}
className="form-control"/>
</div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<input
placeholder="Home Number*"
type="number"
value={this.state.home_num}
onChange={this.handle_homenum}
className="form-control"/>
</div>
<div className="col-md-6">
<input
placeholder="Contact Number*"
type="number"
value={this.state.contact_num}
onChange={this.handle_contactnum}
className="form-control"/>
</div>
</div>
<br/><br/>
<h5><b>Employment Application</b></h5>
<br/>
<div className="row">
<div className="col-md-6">
<p>Position Applying For</p>
{this.renderName()}
</div>
<div className="col-md-6">
</div>
</div>
<br/><br/>
<div className="row">
<div className="col-md-6">
<p>1. What is your current employment status?</p>
<div className="form-check-inline">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Unemployed"/>Unemployed
</label>
</div>
<div className="form-check-inline">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Employed"/>Employed
</label>
</div>
<div className="form-check-inline disabled">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Self-Employed"/>Self-Employed
</label>
</div>
<div className="form-check-inline disabled">
<label className="form-check-label">
<input
type="radio"
className="form-check-input"
name="employmentstatus"
onChange={this.handle_employ_status}
defaultChecked={false}
value="Student"/>Student
</label>
</div>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<p>2. Are you willing to relocate?</p>
<div className="form-check-inline">
<label className="form-check-label">
<input type="radio"
name="relocate"
onChange={this.handle_employ_relocate}
className="form-check-input"
value="Yes"/>Yes
</label>
</div>
<div className="form-check-inline">
<label className="form-check-label">
<input type="radio"
name="relocate"
onChange={this.handle_employ_relocate}
className="form-check-input"
value="No"/>No
</label>
</div>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<p>3. When is your available start date?</p>
<input
name="startdate"
type="date"
onChange={this.handle_employ_start_date}
value={this.state.employ_start_date}
required=""
className="form-control"/>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<p>4. Kindly attach a copy of your resume (PDF,docx files only).</p>
<div className="custom-file">
<input
type="file"
name="file"
accept="application/msword,application/pdf"
onChange={this.handle_employ_file}
className="custom-file-input"
id="inputGroupFile04"/>
<label className="custom-file-label" htmlFor="inputGroupFile04">Choose file</label>
</div>
</div>
<div className="col-md-6"></div>
</div>
<br/>
<div className="row">
<div className="col-md-6">
<input
className="btn btn-outline-primary btn-large form-control col-md-5"
type="submit"
value="Send Application"/>
</div>
<div className="col-md-6"></div>
</div>
</div>
</form>
</div>
)
}
Controller:
public function save_application(Request $request)
{
$firstname = $request->get('firstname');
$lastname = $request->get('lastname');
$middlename = $request->get('middlename');
$email = $request->get('email');
$home_number = $request->get('home_number');
$contact_num = $request->get('contact_num');
$job = $request->get('job');
$employ_status = $request->get('employ_status');
$employ_relocate = $request->get('employ_relocate');
$employ_start_date = $request->get('employ_start_date');
$employ_file = $request->get('employ_file');
$now = new DateTime();
DB::insert('INSERT INTO onlineapplication
(position_name,firstname,middlename,lastname,email,homenumber,phonenumber,employmentstatus,relocate,starting_date,destination,file_img_name,Status)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)',[
$firstname,
$lastname,
$middlename,
$email,
$home_number,
$contact_num,
$job,
$employ_status,
$employ_relocate,
$employ_start_date,
$employ_file
]);
return response()->json('Successfully inserted');
}
When form tag is used, the submit will trigger the default behaviour that is based on the method provided and the action url.
as in your example you are handling the data explicitly you should prevent the default behaviour.
add the below code in handle submit
handleSubmit(e) {
e.preventDefault();
...
...
}
this will prevent the default behaviour.
Improvement for state update:
you don't need individual functions to update the input value to state this can be combined in one function.
to combine, provide the input name same as state name.
this.state ={
"f_name": '',
"l_name": '',
...
}
<input name="f_name" ... onChange={this.handleInputChange}/>
<input name="l_name" .. onChange={this.handleInputChange}/>
handleInputChange(e){
let target = e.target;
let name = target.name;
let value = target.value
this.setState({[name]: value})
}
for more info refer this link.
First, I just want to introduce to you to the arrow function in JavaScript (ES6). Declaring private methods like this:
handle_fname = (e) =>
{
this.setState({
f_name:e.target.value,
})
}
will save you time from unnecessary binding in the constructor.
Regarding your question, you missed to show the content of your this.handleSubmit(). Without this, I can assume that the form submit fired a get call since you failed to put method attribute in your <form/> tag, and without indicating your method attribute will result to default get method. Get method when used, data submitted will be visible in the page address field of your browser.
EDIT
You already added your handleSubmit() in your question, and it looks okay. If data is still shown in the address field of your browser, try adding method="post" in your form tag like this:
<form onSubmit={this.handleSubmit} method="post">

TypeError: Cannot read property 'title' of undefined in React

I have an object which is passed ti the n=modal component in the form
data =[
{
_id: "5ba241b4efa8da2f1464ca81",
title: "Zero To One",
author: "Peter Thiel",
isbn: 1279031943,
__v: 0
}
]
I want to access the title key on the data but when I do I get a TypeError.
I tried converting it to a string using JSON.stringigy() but I still got the same error.
I am trying to access the data within the modal so when the modal opens, the value of the inputs in the modal is set with the data from the Table so I can easily edit them
When I console.log(data[0]) I get the items in the object but as soon as I log console.log(data[0].title) the TypeError appears again.
import React, { Component } from 'react';
import './Update.css';
import Search from '../Search/Search';
// import Modal from './Modal/Modal';
const Table = ({ data, openBookDetails }) => (
<table class="table table-hover">
<thead>
<tr class="table-primary">
<th scope="col">Title</th>
<th scope="col">Author</th>
<th scope="col">ISBN</th>
<th scope="col">No. Of Copies</th>
</tr>
</thead>
<tbody>
{data.map(row =>
<TableRow key={row.id} row={row} openBookDetails={openBookDetails}/>
)}
</tbody>
</table>
)
const TableRow = ({ row, openBookDetails }) => (
<tr class="table-light" onClick={openBookDetails}>
<th scope="row" >{row.title}</th>
<td >{row.author}</td>
<td >{row.isbn}</td>
<td >24</td>
</tr>
)
const Modal = ({ closeBookDetails, isBookDetailsOpen, children, data }) => {
const showHideClassName = isBookDetailsOpen ? 'modal display-block' : 'modal display-none';
console.log(data[0].title);
return (
<div className={showHideClassName}>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Update Book</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label htmlFor="title">Title</label>
<input type="text" class="form-control" id="title" aria-describedby="title" placeholder="Enter title of book" value={data}/>
</div>
<div class="form-group">
<label htmlFor="author">Author</label>
<input type="text" class="form-control" id="author" aria-describedby="author" placeholder="Enter author name" value={data}/>
</div>
<div class="form-group">
<label htmlFor="isbn">ISBN</label>
<input type="number" min="0" class="form-control" id="isbn" aria-describedby="isbn" placeholder="Enter ISBN number" value={data.title}/>
</div>
<div class="form-group">
<label for="copies">Number of Copies</label>
<input type="number" min="0" class="form-control" id="copies" aria-describedby="copies" placeholder="Enter the number of copies" value={data.title}/>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" onClick={closeBookDetails}>Close</button>
</div>
</div>
</div>
{children}
</div>
);
};
class Update extends Component{
constructor(props) {
super(props);
this.state = {
value: '',
suggestions: [],
setOfAllBooks: [],
searchedBooks: [],
isBookDetailsOpen: false,
};
this.setTableData = this.setTableData.bind(this);
this.openBookDetails = this.openBookDetails.bind(this);
this.closeBookDetails = this.closeBookDetails.bind(this);
}
setTableData(searchedBook){
this.setState({searchedBooks: searchedBook})
console.log(this.state.searchedBooks)
}
openBookDetails(){
console.log('openBookDetails')
this.setState({ isBookDetailsOpen: true})
}
closeBookDetails(){
this.setState({ isBookDetailsOpen: false})
}
render(){
return(
<div>
<Search state={this.state} setTableData={this.setTableData} />
<Table data={this.state.searchedBooks} openBookDetails={this.openBookDetails}/>
<Modal data={this.state.searchedBooks} isBookDetailsOpen={this.state.isBookDetailsOpen} closeBookDetails={this.closeBookDetails} />
{/* <Modal /> */}
</div>
)
}
}
export default Update;
When you pass in data as this.state.searchedBooks you are passing in the defined object, but from your code I can't see where you are actually setting the value to the array listed above. Are you missing part of the code?
Doing a console log on this would not return an error if done as console.log(data[0]) but would return a type error for data[0].title or anything other part of this object.
Can you try something like this:
if(data) {
console.log(data[0].title)
}
So we can tell if the response from the server has arrived. Then maybe this will help to make a further assessment.
Also have you considered using an arrow function within the Update component so you can eliminate the need to bind these functions.
class Update extends Component{
constructor(props) {
super(props);
this.state = {
value: '',
suggestions: [],
setOfAllBooks: [],
searchedBooks: [],
isBookDetailsOpen: false,
};
}
setTableData = (searchedBook) => {
this.setState({searchedBooks: searchedBook})
console.log(this.state.searchedBooks)
}
openBookDetails = () => {
console.log('openBookDetails')
this.setState({ isBookDetailsOpen: true})
}
closeBookDetails = () => {
this.setState({ isBookDetailsOpen: false})
}
render(){
return(
<div>
<Search state={this.state} setTableData={this.setTableData} />
<Table data={this.state.searchedBooks} openBookDetails={this.openBookDetails}/>
<Modal data={this.state.searchedBooks} isBookDetailsOpen={this.state.isBookDetailsOpen} closeBookDetails={this.closeBookDetails} />
{/* <Modal /> */}
</div>
)
}
}
Update:
Is the error thrown at that point or later because in the modal component I do see two references to data.title that would throw an error.
changes these lines as follows:
<div class="form-group">
<label htmlFor="isbn">ISBN</label>
<input type="number" min="0" class="form-control" id="isbn" aria-describedby="isbn" placeholder="Enter ISBN number" value={data[0].title}/>
</div>
<div class="form-group">
<label for="copies">Number of Copies</label>
<input type="number" min="0" class="form-control" id="copies" aria-describedby="copies" placeholder="Enter the number of copies" value={data[0].title}/>
</div>
In this case your input is trying to use a value of data.title which doesn't exist. Not sure if this doesn't work.
I found a work around it.
Inside of the Modal I did
let selectedBookDetails = []
data.map(row => selectedBookDetails = row)
And then I accessed the data like this selectedBookDetails.title, selectedBookDetails.author, selectedBookDetails.isbn
Now the next challenge is getting it to edit.
Thanks everyone for your contribution.
Instead use this:
console.log(data[0]?.title)
That will do the trick.

Resources