Trouble in reactjs Update operation - reactjs

I am learning reactjs and going through a trouble to implement update operation. I have added ADD/DELETE but couldn't implement update. When i click on edit button, it appears with the data i clicked on but the problem is, when i submit, the data not adding to my table i submitted but newly added data is adding to table.
only problem with update
here you go for my
form.js file
import React, { Fragment } from "react"
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {name: '', age: '', email: ''};
this.onHandleChange = this.onHandleChange.bind(this);
this.submit = this.submit.bind(this);
}
submit(event, name, age, email) {
if (this.props.submitMe) {
this.props.submitMe(name, age, email);
}
this.setState({name: '', age: '', email: ''}); // clear form after click on submit
}
onHandleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
componentDidUpdate(prevProps){
if(prevProps.currentEmp != this.props.currentEmp){
this.setState({
index: this.props.currentEmp.index,
name: this.props.currentEmp.name,
age: this.props.currentEmp.age,
email: this.props.currentEmp.email,
});
}
}
render() {
return (
<form>
<div className="form-group">
<input onChange={(event) => this.onHandleChange(event)} value={this.state.name} name="name" type="text" />
</div>
<div className="form-group">
<input onChange={(event) => this.onHandleChange(event)} value={this.state.age} name="age" type="number"/>
</div>
<div className="form-group">
<input onChange={(event) => this.onHandleChange(event)} value={this.state.email} name="email" type="text"/>
</div>
<button onClick={(event) => this.submit(event, this.state.name, this.state.age, this.state.email)} type="button">{this.props.currentButtonName}</button>
</form>
);
}
}
export default Form;
here here you go for my table.js file
import React, {Fragment} from "react"
class Table extends React.Component {
constructor(props) {
super(props);
this.state = {
employees: this.props.employees
};
//this.onDelete = this.onDelete.bind(this);
this.onEdit = this.onEdit.bind(this);
}
onEdit(event, index){
if(this.props.editThis){
this.props.editThis(index);
}
}
componentDidUpdate(prevProps){
if(prevProps.employees != this.props.employees){
this.setState({
employees: this.props.employees
});
}
}
render() {
return (
<Fragment>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Age</th>
<th scope="col">Email</th>
<th scope="col">EDIT</th>
<th scope="col">DELETE</th>
</tr>
</thead>
<tbody>
{this.props.employees.map((item, index) => (
<tr key={index}>
<td>{item.name}</td>
<td>{item.age}</td>
<td>{item.email}</td>
<td>
<button
type="button"
onClick={(event) => this.onEdit(event, index)}
className="btn btn-primary btn-sm">EDIT
</button>
</td>
<td>
<button
onClick={(event) => this.props.deleteMe(event, index)}
type="button" className="btn btn-danger btn-sm">DELETE
</button>
</td>
</tr>
))}
</tbody>
</Fragment>
);
}
}
export default Table;
and here you go for my home.js file
import React from "react"
import Table from "./table"
import Form from "./form"
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
current: 'SAVE', // button name
employees: [{name: 'jhon', age: '23', email: 'a#a'}, {name: 'doe', age: '24', email: 'b#a'}],
currentEmp: {},
};
this.onSubmit = this.onSubmit.bind(this);
this.onDelete = this.onDelete.bind(this);
this.setIndex = this.setIndex.bind(this);
}
onSubmit(name, age, email, index=null) {
if(!index && this.state.current == 'SAVE'){
this.setState({ employees: [...this.state.employees, { name: name, age: age, email: email }] });
}
else if(index != null && this.state.current == 'Update'){
var emp = this.state.employees;
emp[index].name = name;
emp[index].age = age;
emp[index].email = email;
this.setState({
currentEmp: {},
employees: emp,
current: 'SAVE'
});
}
else{
this.setState({
currentEmp: {},
current: 'SAVE',
});
}
};
setIndex(index){
var emp = this.state.employees[index];
emp.index = index;
this.setState({
currentEmp: emp,
current: 'Update'
});
}
// delete employee
onDelete(event, index) {
this.setState({
employees: this.state.employees.filter((item, itemIndex) => (index != itemIndex)),
});
};
render() {
return (
<React.Fragment>
<h1>Employee Information System</h1>
<Form currentEmp={this.state.currentEmp} submitMe={this.onSubmit} currentButtonName={this.state.current} />
<hr/>
<table className="table table-striped table-dark">
<Table onUpdateTry={this.edit} editThis={this.setIndex} employees={this.state.employees} deleteMe={this.onDelete} />
</table>
<p className="test">Ignore this please ! Just showed if sass works or not</p>
</React.Fragment>
);
}
}
export default Home;
Can anyone help to fix this? I just screwed up to fix this

Your problem is this line,
else if(index != null && this.state.current == 'Update'){
here you are checking index!=null, but at the time of updation you are never passing any index so your case is false and it will skip this logic.
You just need this condition,
else if(this.state.current == 'Update'){
Also when you call setIndex instead of setting index on actual employee you need to set index in state,
setIndex(index){
var emp = this.state.employees[index];
emp.index = index;
this.setState({
currentEmp: emp,
current: 'Update',
index //set index in state
});
}
And finally your updation logic should be,
else if(this.state.current == 'Update'){
var emp = this.state.employees;
emp[this.state.index].name = name; //use index from state
emp[this.state.index].age = age;
emp[this.state.index].email = email;
this.setState({
currentEmp: {},
employees: emp,
current: 'SAVE'
});
}
Demo

Related

Use react modal bootstrap to edit items in a map list

My application have two components, one renders a list and the other render the form:
I would like to use the same component to create new categories and also to edit the categories that already exists.
The create categories is working fine already, but to edit, needs to pass the id of the category in the list to the form inside the modal, as i am new into react, i would like some help. Thanks in advance.
The list file is called,
Categories.jsx
import React, { Component } from 'react'
import { Alert, Modal, Button } from "react-bootstrap";
import Datatable from '../../../globalcomponents/datatable/Datatable';
import CategoryForm from './CategoryForm';
const Api = require('../../api/CategoriesApi.js')
class Categories extends Component {
constructor(props) {
super(props)
this.state = {
categories: [],
isLoaded: false,
error: null,
isOpen: false
}
}
openModal = () => this.setState({ isOpen: true });
closeModal = () => this.setState({ isOpen: false });
componentDidMount() {
Api.getCategories()
.then(response => {
const [error, data] = response
if (error) {
this.setState({
isLoaded: true,
categories: [],
error: data
})
} else {
this.setState({
isLoaded: true,
categories: data
})
}
})
}
render() {
const { error, isLoaded, categories } = this.state
if (error) {
return (
<Alert color="danger">
Error: {error}
</Alert>
)
} else if (!isLoaded) {
return (
<Alert color="primary">
Loading...
</Alert>
)
} else {
return (
<>
<Button className="float-right" variant="primary" onClick={this.openModal}>
Adicionar
</Button>
<h4 className="mt-4 mb-4">Categorias de investimentos</h4>
<Datatable>
<table className="table table-striped my-4 w-100">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Url (Slug)</th>
<th></th>
</tr>
</thead>
<tbody>
{categories.map(category => (
<tr key={category.id}>
<td>{category.id}</td>
<td>{category.title}</td>
<td>{category.slug}</td>
<td>
<Button className="float-right mr-2" variant="primary" onClick={this.openModal}>
Modal Edit
</Button>
</td>
</tr>
))}
</tbody>
</table>
</Datatable>
<Modal show={this.state.isOpen} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Adicionar / Editar</Modal.Title>
</Modal.Header>
<Modal.Body>
<CategoryForm />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.closeModal}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
)
}
}
}
export default Categories
The form file is used to create or edit categories. And it is called:
CategoryForm.jsx
import React, { Component } from 'react'
import { Redirect } from 'react-router'
import { Row, Col, Alert, Button, Form, FormGroup, Label, Input } from 'reactstrap'
const Api = require('../../api/CategoriesApi.js')
class CategoryForm extends Component {
constructor(props) {
super(props)
this.state = {
category: {
id: this.getCategoryId(props),
title: '',
slug: '',
},
redirect: null,
errors: []
}
this.setTitle = this.setTitle.bind(this)
this.setSlug = this.setSlug.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
getCategoryId(props) {
try {
return props.match.params.id
} catch (error) {
return null
}
}
setTitle(event) {
let newVal = event.target.value || ''
this.setFieldState('title', newVal)
}
setSlug(event) {
let newVal = event.target.value || ''
this.setFieldState('slug', newVal)
}
setFieldState(field, newVal) {
this.setState((prevState) => {
let newState = prevState
newState.category[field] = newVal
return newState
})
}
handleSubmit(event) {
event.preventDefault()
let category = {
title: this.state.category.title,
slug: this.state.category.slug,
}
Api.saveCategory(category, this.state.category.id)
.then(response => {
const [error, errors] = response
if (error) {
this.setState({
errors: errors
})
} else {
this.setState({
// reload categories
redirect: '/admin'
})
}
})
}
componentDidMount() {
if (this.state.category.id) {
Api.getCategory(this.state.category.id)
.then(response => {
const [error, data] = response
if (error) {
this.setState({
errors: data
})
} else {
this.setState({
category: data,
errors: []
})
}
})
}
}
render() {
const { redirect, category, errors } = this.state
if (redirect) {
return (
<Redirect to={redirect} />
)
} else {
return (
<>
<Row>
<Col>
{errors.length > 0 &&
<div>
{errors.map((error, index) =>
<Alert color="danger" key={index}>
{error}
</Alert>
)}
</div>
}
<Form onSubmit={this.handleSubmit}>
<FormGroup>
<Label for="title">Title</Label>
<Input type="text" name="title" id="title" value={category.title} placeholder="Enter title" onChange={this.setTitle} />
</FormGroup>
<FormGroup>
<Label for="slug">Slug</Label>
<Input type="text" name="slug" id="slug" value={category.slug} placeholder="Enter slug" onChange={this.setSlug} />
</FormGroup>
<Button color="success">Submit</Button>
</Form>
</Col>
</Row>
</>
)
}
}
}
export default CategoryForm
You are not passing the id in Categories.jsx. either you can set the id in the history state or do pass it by component
prop drill.
setting the state in history Programmatically set params in React Router v4
Or You can do Pass the id to the Component and handle in Component
DidMount Event.
here is the code sandbox link
Categories.jsx
/** Create a id variable in state. **/
class Categories extends Component {
constructor(props) {
super(props);
this.state = {
categories: [],
isLoaded: false,
error: null,
isOpen: false,
--> id: null <--
};
}
/** change the openModal code to something like this. **/
openModal = (id) => {
this.setState( (prev) => {
const state = prev.state;
return { ...state, id: id, isOpen:true };
});
};
/** while Onclick set the id in the state. **/
<Datatable>
<table className="table table-striped my-4 w-100">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Url (Slug)</th>
<th></th>
</tr>
</thead>
<tbody>
{categories.map((category) => (
<tr key={category.id}>
<td>{category.id}</td>
<td>{category.title}</td>
<td>{category.slug}</td>
<td>
<Button
className="float-right mr-2"
variant="primary"
--> onClick={() =>this.openModal(category.id)}
>
Modal Edit
</Button>
</td>
</tr>
))}
</tbody>
</table>
</Datatable>
/** Pass the id prop for CategoryForm Component in Modal body from the state. **/
<Modal show={this.state.isOpen} onHide={this.closeModal} >
<Modal.Header closeButton>
<Modal.Title>Adicionar / Editar</Modal.Title>
</Modal.Header>
<Modal.Body>
--> <CategoryForm id={this.state.id || null} />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick= {this.closeModal}>
Close
</Button>
</Modal.Footer>
</Moddal>
CategoryForm.jsx
In the componentDidMount conditionally check if there is id variable in props.
componentDidMount() {
**// Check if props.id is available**
if (** this.state.category.id || this.props.id **) {
**const id = this.state.category.id || this.props.id;**
Api.getCategory(id).then((response) => {
const [error, data] = response;
if (error) {
this.setState({
errors: data
});
} else {
alert(id);
this.setState({
category: data,
errors: []
});
}
});
}
}
You can add more state to Categories to keep track of additional data about the modal.
*I have only included the highlights in the code here; lots was left out for brevity.
In Categories.jsx:
constructor(props) {
super(props)
this.state = {
categories: [],
isLoaded: false,
error: null,
isOpen: false,
modalData: null,
}
}
openModal = (modalData) => this.setState({ isOpen: true, modalData });
closeModal = () => this.setState({ isOpen: false, modalData: null });
//'create' dialog button
<Button className="float-right" variant="primary" onClick={e => this.openModal({modalType: 'create'})}>
Adicionar
</Button>
//here are the table rows:
{categories.map(category => (
<tr key={category.id}>
<td>{category.id}</td>
<td>{category.title}</td>
<td>{category.slug}</td>
<td>
<Button className="float-right mr-2" variant="primary" onClick={e => this.openModal({modalType: 'edit', categoryId: category.id})}>
Modal Edit
</Button>
</td>
</tr>
))}
//the modal. pass modalData as a prop:
<Modal show={this.state.isOpen} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Adicionar / Editar</Modal.Title>
</Modal.Header>
<Modal.Body>
<CategoryForm modalData={modalData} />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.closeModal}>
Close
</Button>
</Modal.Footer>
</Modal>
In CategoryForm.jsx:
//get id from props:
getCategoryId(props) {
return (props.modalData.modalType === 'edit') ? props.modalData.categoryId : false;
//I don't know if this needs to be here:
//try {
// return props.match.params.id
//} catch (error) {
// return null
//}
}
You might have to refactor CategoryForm.jsx. For instance, the categoryId is now a prop, so it doesn't need to be duplicated in state.

Cannot Update Data in Reactjs+Laravel App

I have an offer-adding feature in my app. my front end is on react js and the backend is on Laravel. I have created a route to update the data and called it using Axios but I don't know what I am doing wrong. Any type of Help will be appreciated Thank You!
this is my route in api.php
Route::put('offers/{id}', 'Api\Offer\OfferController#update');
This is my OfferController
public function update(Request $request, $id)
{
$offer = Offer::findOrFail($id);
$offer->update($request->all());
return $offer;
}
This is my API call function for update
export const updateItem = (offertitle,offerdescription,vid,id) => {
return axios
.put(
`/api/offers/${id}`,
{
offertitle:offertitle,
offerdescription:offerdescription,
vid:vid
},
{
headers: { 'Content-Type': 'application/json' }
}
)
.then(function (response) {
console.log(response)
})
}
OfferComponent
export default class Offer extends React.Component{
constructor() {
super()
this.state = {
offertitle: '',
offerdescription: '',
editDisabled: false,
offers: [],
redirect: false,
vid:'',
offerid:''
}
this.onSubmit = this.onSubmit.bind(this)
this.onChange = this.onChange.bind(this)
}
componentDidMount() {
this.getAll()
if (sessionStorage.getItem('user')) {
vendorprofile().then(res => {
this.setState({
vid: res.user.vid
})
})
}
else {
this.setState({ redirect: true });
}
}
onChange = e => {
this.setState({
[e.target.name]: e.target.value
})
}
getAll = () => {
getList().then(data => {
this.setState(
{
offertitle:'',
offerdescription:'',
offers: [...data]
},
() => {
console.log(this.state.offers)
}
)
})
}
onSubmit = e => {
e.preventDefault()
addItem({offertitle: this.state.offertitle, offerdescription: this.state.offerdescription,vid: this.state.vid}).then(() => {
this.getAll()
})
this.setState({
offertitle: '',
offerdescription:'',
vid:''
})
}
onUpdate = e => {
e.preventDefault()
updateItem({ offertitle: this.state.offertitle, offerdescription: this.state.offerdescription, offerid: this.state.offerid, vid: this.state.vid }).then(() => {
this.getAll()
})
this.setState({
offertitle: '',
offerdescription: '',
vid:'',
editDisabled: ''
})
this.getAll()
}
onEdit = (offerid, e) => {
e.preventDefault()
var data = [...this.state.offers]
data.forEach((offers,index) => {
if (offers.offerid === offerid) {
this.setState({
offerid: offers.offerid,
offertitle: offers.offertitle,
offerdescription: offers.offerdescription,
editDisabled: true
})
}
})
}
onDelete = (val, e) => {
e.preventDefault()
deleteItem(val)
var data = [...this.state.offers]
data.filter(function (offers, index) {
if (offers.offerid === val) {
data.splice(index, 1)
}
return true
})
this.setState({ offers: [...data] })
}
render() {
if (this.state.redirect) {
return (
<Redirect to="/stsignin" />
)
}
return (
<div>
<Pane />
<div className="container" style={{ marginTop : 150}}>
<form>
<div className="form-group">
<div className="row">
<div className="col-md-12">
<label>OFFER TITLE</label>
<input
type="text"
className="form-control"
id="offertitle"
name="offertitle"
value={this.state.offertitle || ''}
onChange={this.onChange.bind(this)}
/>
<label>OFFER DESCRIPTION</label>
<input
type="text"
className="form-control"
id="offerdescription"
name="offerdescription"
value={this.state.offerdescription || ''}
onChange={this.onChange.bind(this)}
/>
</div>
</div>
</div>
{!this.state.editDisabled ? (
<button
type="submit"
onClick={this.onSubmit.bind(this)}
className="btn btn-success btn-block"
>
Submit
</button>
) : (
''
)}
{this.state.editDisabled ? (
<button
type="submit"
onClick={this.onUpdate.bind(this)}
className="btn btn-primary btn-block"
>
Update
</button>
) : (
''
)}
</form>
<table className="table">
<tbody>
<tr>
<th>OFFER_TITLE</th>
<th>OFFER_DESCRIPTION</th>
</tr>
{this.state.offers.map((offers,index) => (
<tr key={index}>
<td className="text-left">{offers.offertitle}</td>
<td className="text-left">{offers.offerdescription}</td>
<td className="text-right">
<button
href=""
className="btn btn-info mr-1"
disabled={this.state.editDisabled}
onClick={this.onEdit.bind(
this,
offers.offerid
)}
>
Edit
</button>
<button
href=""
className="btn btn-danger"
disabled={this.state.editDisabled}
onClick={this.onDelete.bind(
this,
offers.offerid
)}
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)
}
}```
Error 404 Might mean that the offer specified in the link doesn't exist and thus can't be updated. Check if you have an order with the id that you are searching in the database. However, posting your entire response might show us more information. A simple 404 is pretty vague, you might want to copy paste that in.
That being said, i recommend using Eloquent for these kind of routes. You can basically change your route to /offers/{offer} and then instead of typing $id as a variable for that function and then finding the offer by id you can just simply query $offer->update(your_data) and it would work as expected. It is exactly the same thing but just keeps it cleaner and removes any basic mistakes

Set Component State Synchronously on ComponentWIllReveiveProps

I am passing props from Dashboard component to Modal Component when I click an item in the Dahboard table row. When the row is clicked, the data in that row is passed as props to the modal and the modal set its state on ComponenentWIllReceiveProps synchronously so it renders in the Modal Input box and textarea
How do I set the state in modal with props passed down from Dashboard.js and render them in the modal inpputbox and textarea
Dashboard.js
import React, { Component } from 'react'
import Modal from '../Modal/Modal'
import add from '../../images/add.png'
import addSelected from '../../images/addSelected.png'
import './Dashboard.css'
const TableRow = ({ row, openQuoteDetails, deleteQuote }) => (
<tr>
<th scope="row" onClick={openQuoteDetails}>{row.author}</th>
<td onClick={openQuoteDetails}>{row.quote}<small id="admin" className="form-text text-muted">{row.admin}</small></td>
<td><i className="fa fa-close" onClick={deleteQuote}></i></td>
</tr>
)
const Table = ({ data, openQuoteDetails, deleteQuote }) => (
<table className="table table-hover">
<thead>
<tr className="table-active">
<th scope="col">Author</th>
<th scope="col">Quote</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{data.map((row, index) =>
<TableRow key={index} row={row} openQuoteDetails={() => openQuoteDetails(row, index)} deleteQuote={() => deleteQuote(row, index)} />
)}
</tbody>
</table>
)
class Dashboard extends Component {
constructor() {
super()
this.state = {
quotes: [
{
"quote": "Our industry does not respect tradition - it only respects innovation.",
"author": "Satya Nadella",
"admin": "Joseph Akayesi"
},
{
"quote": "Engineering is the closest thing to magic that exists in the world.",
"author": "Elon Musk",
"admin": "Joseph Akayesi"
},
{
"quote": "For me, it matters that we drive technology as an equalizing force, as an enabler for everyone around the world.",
"author": "Sundar Pichai",
"admin": "Yasmin Adams"
}
],
addSource: add,
isModalOpen: false,
index: '',
author: '',
quote: ''
}
}
onAddMouseOver = () => {
this.setState({ addSource: addSelected })
}
onAddMouseOut = () => {
this.setState({ addSource: add })
}
toggleModalOpenOrClose = () => {
this.setState({ isModalOpen: !this.state.isModalOpen })
this.setState({ index: '' })
this.setState({ author: '' })
this.setState({ quote: '' })
}
openQuoteDetails = (row, index) => {
this.setState({ isModalOpen: true });
this.setState({ index: index, author: row.author, quote: row.quote })
}
deleteQuote = (row, index) => {
this.setState({ isModalOpen: false })
console.log('Row deleted')
console.log(this.state.quotes.splice(index, 1))
}
render() {
return (
<div className='pt-3'>
<Table
data={this.state.quotes}
openQuoteDetails={this.openQuoteDetails}
deleteQuote={this.deleteQuote} />
<div className='text-center align-items-center justify-content-centerpt-5'>
<a href='#add' onClick={this.toggleModalOpenOrClose}>
<img src={this.state.addSource} className='addButton mx-1' alt="add" onMouseOver={this.onAddMouseOver} onMouseOut={this.onAddMouseOut} />
</a>
</div>
<Modal
isModalOpen={this.state.isModalOpen}
toggleModalOpenOrClose={this.toggleModalOpenOrClose}
data={this.state}
onInputChange={this.onInputChange}
addNewQuote={this.addNewQuote}
updateExistingQuote={this.updateExistingQuote} />
</div>
)
}
}
export default Dashboard
Modal.js
import React, { Component } from 'react'
import './Modal.css'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { addQuote } from '../../actions/quoteActions'
class Modal extends Component {
constructor(props) {
super(props)
this.state = {
id: '',
author: '',
quote: '',
errors: {}
}
}
onInputChange = (event) => {
this.setState({ [event.target.id]: event.target.value })
}
switchSaveChangesAction = () => {
return this.props.state.index ? this.addNewQuote : this.updateExistingQuote
}
addNewQuote = () => {
const { user } = this.props.auth
const newQuote = {
admin: user.id,
quote: this.state.quote,
author: this.state.author,
}
console.log('Add New')
console.log(newQuote)
}
componentWillReceiveProps(nextProps) {
console.log('receive props')
if(nextProps.author !== this.props.author){
this.setState({ author: nextProps.author})
}
// this.setState({ id: this.props.data.index })
console.log(nextProps)
this.setState({ author: this.props.data.author }, () => console.log(this.state.author))
console.log(this.state)
}
updateExistingQuote = (index) => {
console.log('Update Existing')
console.log(this.props.state.author)
console.log(this.props.state.quote)
console.log(this.props.state.index)
}
render() {
let showOrHideModal = this.props.isModalOpen ? 'modal d-block' : 'modal d-none'
// let selectedQuoteDetails = {
// id: this.props.data.index ? this.props.data.index : '',
// author: this.props.data.author ? this.props.data.author : '',
// quote: this.props.data.quote ? this.props.data.quote : ''
// };
// let modalInputValue = selectedQuoteDetails ? selectedQuoteDetails : this.state
let saveChangesAction = this.props.data.index >= 0 ? this.updateExistingQuote : this.addNewQuote
return (
<div className={showOrHideModal}>
<div className='modal-dialog' role='document'>
<div className='modal-content'>
<div className='modal-header bg-light'>
<h5 className='modal-title'><b>Add a Quote</b></h5>
<button type='button' className='close' data-dismiss='modal' aria-label='Close' onClick={this.props.toggleModalOpenOrClose}>
<span aria-hidden='true'>×</span>
</button>
</div>
<div className='modal-body'>
<div className='form-group'>
<label htmlFor='author'>Author</label>
<input type='text' className='form-control' id='author' aria-describedby='emailHelp' placeholder='Enter author' onChange={this.onInputChange} defaultValue={this.state.author} />
</div>
<div className='form-group'>
<label htmlFor='quote'>Quote</label>
<textarea className='form-control' id='quote' rows='3' placeholder='Enter quote' onChange={this.onInputChange} value={this.state.quote}></textarea>
</div>
</div>
<div className='modal-footer'>
<button type='button' className='btn btn-primary' onClick={saveChangesAction}>Save changes</button>
<button type='button' className='btn btn-secondary' data-dismiss='modal' onClick={this.props.toggleModalOpenOrClose}>Close</button>
</div>
</div>
</div>
</div>
)
}
}
Modal.propTypes = {
addQuote: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
}
const mapStateToProps = state => ({
auth: state.auth,
errors: state.errors
})
export default connect(mapStateToProps, { addQuote })(Modal)

Adding multiple form fields to array in React

I have a React form that currently stores one form fields value in the items array. However, when adding more than one field, I can't get the content of the other fields to be stored in the array as well. It currently stores the value of the First Name input, but can't figure out the Last Name and Phone fields. The data is then rendered to the items array to a 3 column table, but can't get the other fields to show in their respective columns.
Contacts.js
import ContactList from "./ContactList";
class Contacts extends Component {
constructor(props) {
super(props);
this.state = {
items: []
};
this.addItem = this.addItem.bind(this);
this.deleteItem = this.deleteItem.bind(this);
}
addItem(e) {
if(this._inputElement.value !== "") {
var newItem = {
firstname: this._inputElement.value,
lastname: this._inputElement2.value,
phonename: this._inputElement3.value,
key: Date.now()
};
this.setState((prevState) => {
return {
items: prevState.items.concat(newItem)
};
});
this._inputElement.value = "";
this._inputElement2.value = "";
this._inputElement3.value = "";
}
console.log(this.state.items);
e.preventDefault();
}
deleteItem(key) {
var filteredItems = this.state.items.filter(function (item) {
return (item.key !== key);
});
this.setState({
items: filteredItems
});
}
render () {
return (
<Panel>
<Tabs onChange={this.onChange} defaultSelectedIndex={0} justified={true}>
<Tab value="pane-1" label="Add Contact" onActive={this.onActive}>
<Form onSubmit={this.addItem}>
<input ref={(a) => this._inputElement = a}
placeholder="First Name" />
<input ref={(a) => this._inputElement2 = a}
placeholder="Last Name" />
<input ref={(a) => this._inputElement3 = a}
placeholder="Phone" />
<Button variant="raised">Add</Button>
</Form>
</Tab>
<Tab value="pane-2" label="List Contacts">
<ContactList entries={this.state.items}
delete={this.deleteItem}/>
</Tab>
</Tabs>
</Panel>
);
}
}
export default Contacts
Contact List
class ContactList extends Component {
constructor(props) {
super(props);
this.createContact = this.createContact.bind(this);
}
delete(key) {
this.props.delete(key);
}
createContact(item) {
return
<tr key={item.key}>
<td onClick={() => this.delete(item.key)}>{item.firstname}</td>,
<td>{item.lastname}</td>
<td>{item.phone}</td>
</tr>
}
render() {
var contactEntries = this.props.entries;
var listItems = contactEntries.map(this.createContact);
return (
<table className="mui-table">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr>
{listItems}
</tr>
</tbody>
</table>
);
}
};
export default ContactList;
Here is the answer. You are just hitting this._inputElement ref only saving its value whereas in your form you have two more inputs. My suggestion check latest updates react updates. They don't advice you to use "REF" at all.
addItem(e) {
if (this._inputElement.value !== "") {
var newItem = {
firstname: this._inputElement.value,
lastname: this._inputElement2.value,
phonename: this._inputElement3.value,
key: Date.now()
};
this.setState(prevState => {
return {
items: prevState.items.concat(newItem)
};
});
this._inputElement.value = "";
this._inputElement2.value = "";
this._inputElement3.value = "";
}

Failed prop type: Invalid prop `params` of type `object` supplied to `SignUp`, expected `array`

I am getting this proptype validation error "Invalid prop" if I set it to receive array then It will show expected array but receive object and in other case same error expected function but receive object.
In (signupData : PropTypes.object || PropTypes.array) this warning
related to if I set PropTypes for only Object then error
is " Invalid prop params of type object" and
if set PropTypes for Array then error is " Invalid prop
params of type object". any body have solution?
import React,{PropTypes} from 'react';
import { connect } from "react-redux";
import * as AuthAction from "../../actions/authActions";
import * as step2DataActions from "../../actions/step2DataActions";
import update from 'react-addons-update';
class SIGNUP extends React.Component{
constructor(props){
super(props);
this.state = {
teacherId:props.signupData.teacherId,
data: props.signupData.step4.data,
endTime: props.signupData.step4.endTime,
head: props.signupData.step4.head,
errorInput:'',
errorField: '',
valid: true,
};
}
submitStepSignupForm(){
let step3 = {single_classes:false,multiple_classes:true};
let step4 = {head:this.state.head,startTime:this.state.startTime,endTime:this.state.endTime,data:this.state.data};
let submitData = {};
submitData['teacher_id'] = this.state.teacherId;
submitData['firstname'] = this.props.signupData.firstname;
submitData['lastname'] = this.props.signupData.lastname;
submitData['state'] = this.props.signupData.State;
submitData['zipcode'] = this.props.signupData.zipcode;
submitData['prefix'] = this.props.signupData.prefix;
submitData['step2'] = this.props.step2Data;
submitData['step3'] = step3;
submitData['step4'] = step4;
this.props.signupStep4(submitData);
}
closeModal(){
this.props.scheduleData.dataExist = false;
}
render(){
let tableStyle = {
align:"center"
};
let list = this.state.data.map((p,index) =>{
return (
<tr className="grey2" key={index}>
{Object.keys(p).filter(k => k !== 'id').map(k => {
return (<td className="grey1" key={p.id+''+k}><div suppressContentEditableWarning="true" contentEditable="true"
value={k} onInput={this.editColumn.bind(this,{p},{k})}>{p[k]}</div></td>);
})}
</tr>
);
});
let startList = null;
startList = this.state.startTime.map((obj,index)=>{
let keyName = Object.keys(obj)[0];
return(
<td className="" key={index}><TimePicker start="08:00" end="18:00" step={1} name="C1StartTime" value={obj.StartTime} onChange={this.changeStartTime.bind(this,index,keyName)} /></td>
);
});
let endList = null;
endList = this.state.endTime.map((obj,index)=>{
let keyName = Object.keys(obj)[0];
return(
<td className="" key={index}><TimePicker start="08:00" end="18:00" step={1} value={obj.EndTime} onChange={this.changeEndTime.bind(this,index,keyName)} /></td>
);
});
let head = null;
head = this.state.head.map((obj,index)=>{
return (
<td className="grey1" key={index}>{obj['class']}</td>
);
});
return (
<fieldset className="step-4">
<div className="heading">
<h3>Tell us about your schedule</h3>
{/*<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit </p>*/}
</div>
<div className="schedule table-responsive">
<table cellSpacing="3" id="mytable" style={tableStyle}>
<tbody>
<tr className="grey2" >
{head}
</tr>
<tr className="grey2" >
<td className="">Start Time</td>
{startList}
</tr>
<tr className="grey2" >
<td className="">End Time</td>
{endList}
</tr>
{list}</tbody>
</table>
<p><a id="add_row" className="btn btn-default" onClick={this.appendColumn}>Add +</a>
<a id="add_row" className="btn btn-default" onClick={this.removeColumn}>Remove -</a>
<span className="inputError" >{this.state.errorInput}</span>
<span className="inputError" >{this.state.errorField}</span>
</p>
</div>
<input type="button" name="previous" className="previous pre-btn action-button" value="Previous" />
{(this.state.valid)?(<input type="submit" name="submit" className="submit1 action-button1" value="Submit" onClick={this.submitStepSignupForm.bind(this)}/>):(<input type="submit" name="submit" className="disable-step4" value="Submit" />)}
</fieldset>
);
}
}
STEP4SIGNUP.propTypes = {
signupData : PropTypes.object || PropTypes.array,
getSchedule : PropTypes.object || PropTypes.array,
step2Data : PropTypes.object || PropTypes.array,
scheduleData : PropTypes.object || PropTypes.array,
signupStep4 : PropTypes.func
};
const mapStateToProps = (state) => {
return {
user: state,
step2Data: state.step2Data.step2Data,
scheduleData: state.step2Data.scheduleData,
step4Data: state.step4Reducer.step4
};
};
const mapDispatchToProps = (dispatch) => {
return {
signupStep4: submitData => dispatch(AuthAction.signupStep4(submitData)),
getSchedule: (teacher_id) => dispatch(step2DataActions.getSchedule(teacher_id)),
};
};
export default connect(mapStateToProps,mapDispatchToProps)(STEP4SIGNUP);
when you write signupData : PropTypes.object || PropTypes.array you're basically saying
if(PropTypes.object){
return PropTypes.object;
} else {
return PropTypes.array;
}
in other words, since PropTypes.object will always evaluate to true you're declaring your prop as PropTypes.object all the time.
if you want to validate a prop against more than one type, use oneOfType
// An object that could be one of many types
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
])

Resources