Editing Data from Row with React/Semantic UI - reactjs

Still new in React and im in the middle of my practice creating table components, the task is: input, delete and edit data.
input data row is working
delete data row is working
edit data not working,
i can manage to get the value, but i can't edit it.
the code still messy too, but it works from point 1 to 2.
Here is the code. Hope you guys can point out my mistakes and maybe some tips to tidy up this code to make it more cleaner.
Thanks
//Table.js//
import React, { Component } from 'react'
import { Table, Icon, Button, Modal, Form } from 'semantic-ui-react'
import 'semantic-ui-css/semantic.min.css'
import { DateInput } from 'semantic-ui-calendar-react'
import './Tables.css'
var database = [
{
DocNum: 123,
DocTyp: 'Permit',
DocName: 'Permit A',
SignDate: '2007-11-05',
ExprDate: '2012-11-05'
},
{
DocNum: 456,
DocTyp: 'Permit',
DocName: 'Permit C',
SignDate: '2010-02-11',
ExprDate: '2015-02-11'
},
{
DocNum: 789,
DocTyp: 'Contract',
DocName: 'Contract Z',
SignDate: '2017-06-08',
ExprDate: '2022-06-08'
}
]
const options = [
{ key: 1, text: 'Permit', value: 'Permit' },
{ key: 2, text: 'Contract', value: 'Contract' },
]
const initialState = { open: false,
open2: false,
open3: false,
open4: false,
DocNum: '',
DocTyp: '',
DocName: '',
SignDate: '',
ExprDate: '',
del:'',
edit:''
}
function Addbtn ({ onShow3 }) {
return(
<Button content='Add Document' icon='plus' labelPosition='left' color="green" onClick={onShow3} />
)
}
function InputData ({ onChange, onSubmit, DataInput}) {
return (
<Form className="InputContainer">
<Form.Input label="Document Number" type="text" name="DocNum" onChange={onChange} />
<Form.Select label="Document Type" type="text" name="DocTyp" onChange={onChange} options={options} />
<Form.Input label="Document Name" type="text" name="DocName" onChange={onChange} />
<DateInput label="Signed Date" name="SignDate" onChange={onChange} value={DataInput[0].SignDate}/>
<DateInput label="Expired Date" name="ExprDate" onChange={onChange} value={DataInput[0].ExprDate}/>
</Form>
)
}
function EditData ({ onChange, onSubmit, DataEdit }) {
return (
<Form className="InputContainer">
<Form.Input label="Document Number" type="text" name="DocNum" onChange={onChange} value={DataEdit.DocNum}/>
<Form.Select label="Document Type" type="text" name="DocTyp" onChange={onChange} options={options} value={DataEdit.DocTyp} />
<Form.Input label="Document Name" type="text" name="DocName" onChange={onChange} value={DataEdit.DocName} />
<DateInput label="Signed Date" name="SignDate" onChange={onChange} value={DataEdit.SignDate}/>
<DateInput label="Expired Date" name="ExprDate" onChange={onChange} value={DataEdit.ExprDate}/>
</Form>
)
}
function RowData(props) {
const database = props.database
const RowList = database.map((data)=>
<Table.Row key={data.DocNum}>
<Table.Cell>{data.DocNum}</Table.Cell>
<Table.Cell>{data.DocTyp}</Table.Cell>
<Table.Cell>{data.DocName}</Table.Cell>
<Table.Cell>{data.SignDate}</Table.Cell>
<Table.Cell>{data.ExprDate}</Table.Cell>
<Table.Cell className="icon" collapsing>
<Icon color='yellow'
name='edit'
link
onClick={()=>props.onShow(data)}
/>
<Icon color='red'
name='trash'
link
key={data.DocNum}
onClick={()=>props.onShow2(data)}
/>
</Table.Cell>
</Table.Row>
)
return RowList
}
class TableComponent extends Component{
state = initialState
show = (data) => {
this.setState({ open: true,
edit: data })
}
show2 = (data) => {
this.setState({ open2: true,
del: data })
}
show3 = () => {
this.setState({ open3: true })
}
show4 = (data) => {
this.setState({ open4: true })
this.close()
}
close = () => {
this.setState({ open: false })
}
close2 = () => {
this.setState({ open2: false })
}
close3 = () => {
this.setState({ open3: false })
}
close4 = () => {
this.setState({ open4: false })
}
InputChange = (e, DataInput) => {
this.setState({ [DataInput.name]: DataInput.value })
}
SearchDel = () =>{
for(let i=0; i<database.length; i++){
if (this.state.del === database[i])
return database.splice(i, 1)}
}
DelData = () =>{
return ( this.SearchDel(),
this.close2())
}
Submit = (data) => {
return (database.push(data),
this.close3())
}
render(){
return(
<div className='MainContainer'>
<div className="TblContainer">
<div className="AddButton">
<Addbtn onShow3={this.show3}/>
</div>
<Table color="red" celled >
<Table.Header>
<Table.Row>
<Table.HeaderCell collapsing>Document Number</Table.HeaderCell>
<Table.HeaderCell width={2}>Document Type</Table.HeaderCell>
<Table.HeaderCell width={6}>Document Name</Table.HeaderCell>
<Table.HeaderCell collapsing>Signed Date</Table.HeaderCell>
<Table.HeaderCell collapsing>Expired Date</Table.HeaderCell>
<Table.HeaderCell collapsing />
</Table.Row>
</Table.Header>
<Table.Body>
<RowData database={database} onShow={this.show} onShow2={this.show2} />
</Table.Body>
</Table>
<Modal open={this.state.open} onClose={this.state.close} id="Modal1">
<Modal.Header>Edit Data</Modal.Header>
<Modal.Content>
<p>Are you sure you want to edit this?</p>
</Modal.Content>
<Modal.Actions>
<Button negative onClick={this.close}>No</Button>
<Button positive onClick={this.show4}>Yes</Button>
</Modal.Actions>
</Modal>
<Modal open={this.state.open2} onClose={this.state.close2} value={this.state} id="Modal2">
<Modal.Header>Delete Data</Modal.Header>
<Modal.Content>
<p>Are you sure you want to delete this?</p>
</Modal.Content>
<Modal.Actions>
<Button negative onClick={this.close2}>No</Button>
<Button positive onClick={()=>this.DelData()}>Yes</Button>
</Modal.Actions>
</Modal>
<Modal open={this.state.open3} onClose={this.state.close3} id="Modal3">
<Modal.Header>Inputing Data</Modal.Header>
<Modal.Content>
<InputData onChange={this.InputChange}
onSubmit={this.Submit}
DataInput={[this.state]} />
</Modal.Content>
<Modal.Actions>
<Button negative onClick={this.close3}>No</Button>
<Button positive onClick={()=>this.Submit(this.state)}>Submit</Button>
</Modal.Actions>
</Modal>
<Modal open={this.state.open4} onClose={this.state.close4} id="Modal4">
<Modal.Header>Editing Data</Modal.Header>
<Modal.Content>
<EditData onChange={this.InputChange}
onSubmit={this.Submit}
DataEdit={this.state.edit} />
</Modal.Content>
<Modal.Actions>
<Button negative onClick={this.close4}>No</Button>
<Button positive onClick={()=>this.Submit(this.state)}>Submit</Button>
</Modal.Actions>
</Modal>
</div>
</div>
)
}
}
export default TableComponent
//Table.css//
.TblContainer{
margin: 100px;
}
.AddButton{
display: flex;
justify-content: flex-end;
}

Related

Why am i POST a lot of unwanted data?

I'm kind of new with java and ReactJS and I have a big issue where when I tried to post my data, it posted a lot of unwanted data like rendering the whole table.
My console.log() printed this :
location_dest_id: 2
location_id: 1
origin: "test3"
picking_type_id: 1
stock_move_ids: Array(1)
0:
altKey: false
bubbles: true
button: 0
buttons: 0
cancelable: true
clientX: 317
clientY: 652
ctrlKey: false
currentTarget: null
defaultPrevented: false
demand: "12"
detail: 1
done: "0"
eventPhase: 3
getModifierState: ƒ modifierStateGetter(keyArg)
isDefaultPrevented: ƒ functionThatReturnsFalse()
isPropagationStopped: ƒ functionThatReturnsFalse()
isTrusted: true
metaKey: false
movementX: 0
movementY: 0
nativeEvent: PointerEvent {isTrusted: true, pointerId: 1, width: 1,
height: 1, pressure: 0, …}
pageX: 317
pageY: 754
product_tmpl_id: 9
product_uom: "1"
relatedTarget: null
screenX: 317
screenY: 723
shiftKey: false
target: span
timeStamp: 203547.59999990463
type: "click"
view: Window {window: Window, self: Window, document: document, name: '', location: Location, …}
_reactName: "onClick"
_targetInst: null
From what I understand, the error is when I tried to pass "stock_move_ids" nested data, it POST so much data as like the console.log() above. What it should be passed is like this :
[
{
"date":"02-09-2022",
"origin":"test2",
"picking_type_id":2,
"location_id":1,
"location_dest_id":2,
"stock_move_ids":
[
{
"demand":12,
"done":0,
"product_uom":1,
"product_tmpl_id":18
}
]
}
]
Is there any way to solve my problem? My code is based on this template : https://codesandbox.io/s/j0opp
Here's my code looks like :
Parent
import React, { useEffect, useContext } from "react";
import { Button, Form, Input, DatePicker, Select } from 'antd';
import { Stockmovetable } from "./Stockmovetable";
import { AppContext } from '../../../context/Appcontext'
const Stockpickingnew = ({ title }) => {
const { Function, State } = useContext(AppContext)
const { fetchDataPickingType, fetchDataLocation, fetchDataPupuk, option, stock_move_ids, StockPick, StockPickFailed } = Function
const { dateFormat, dataPupuk, dataStockLocation, dataStockPickingType } = State
useEffect(() => {
fetchDataPickingType()
fetchDataLocation()
fetchDataPupuk()
}, [])
return (
<>
<div className='new'>
<div className="top">
<h1>{title}</h1>
</div>
<div className="bottom">
<div className="stockPicking">
<Form
name="stockPickings"
layout="vertical"
onFinish={StockPick}
onFinishFailed={StockPickFailed}
autoComplete="off"
>
<div className="left">
<Form.Item
label="Origin :"
name='origin'
>
<Input placeholder="Origin" />
</Form.Item>
<Form.Item
label="Picking Type :"
name='picking_type_id'
>
<Select
placeholder="Picking Type"
options={dataStockPickingType.map(e => ({label: e.name, value: e.id}))}
/>
</Form.Item>
<Form.Item
label="Date :"
name='date'
>
<DatePicker
format={dateFormat}
/>
</Form.Item>
</div>
<div className="right">
<Form.Item
label="Location :"
name='location_id'
>
<Select
placeholder="Tujuan Awal"
options={dataStockLocation.map(e => ({label: e.name, value: e.id}))}
/>
</Form.Item>
<Form.Item
label="Destination :"
name='location_dest_id'
>
<Select
placeholder="Tujuan Akhir"
options={dataStockLocation.map(e => ({label: e.name, value: e.id}))}
/>
</Form.Item>
</div>
<div className="stockMove">
<Form.List name="stock_move_ids">
{(stock_move_ids, { add, remove }) => {
return <Stockmovetable stock_move_ids={stock_move_ids} option={option} add={add} remove={remove} dataPupuk={dataPupuk} />;
}}
</Form.List>
</div>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</div>
</div>
</div>
</>
)
}
export default Stockpickingnew
Child
import React from "react";
import { Form, Input, Button, Table, Select } from "antd";
import { PlusOutlined, MinusOutlined } from "#ant-design/icons";
const { Column } = Table;
export const Stockmovetable = props => {
const { stock_move_ids, add, remove, dataPupuk, option } = props;
return (
<Table
dataSource={stock_move_ids}
pagination={false}
footer={() => {
return (
<Form.Item>
<Button onClick={add}>
<PlusOutlined /> Add field
</Button>
</Form.Item>
);
}}
>
<Column
dataIndex={"product_tmpl_id"}
title={"Nama Produk"}
render={(value, row, index) => {
return (
<Form.Item name={[index, "product_tmpl_id"]}>
<Select
placeholder="Produk"
options={dataPupuk.map(e => ({ label: e.name, value: e.id }))}
/>
</Form.Item>
);
}}
/>
<Column
dataIndex={"demand"}
title={"Demand"}
render={(value, row, index) => {
// console.log(row);
return (
<Form.Item name={[index, "demand"]}>
<Input
placeholder="Demand"
/>
</Form.Item>
);
}}
/>
<Column
dataIndex={"done"}
title={"Done"}
render={(value, row, index) => {
return (
<Form.Item name={[index, "done"]}>
<Select
placeholder="Tujuan Akhir"
options={option}
/>
</Form.Item>
);
}}
/>
<Column
dataIndex={"product_uom"}
title={"product_uom"}
render={(value, row, index) => {
return (
<Form.Item name={[index, "product_uom"]}>
<Input
placeholder="product_uom"
/>
</Form.Item>
);
}}
/>
<Column
title={"Action"}
render={(value, row, index) => {
return (
<React.Fragment>
<Button
icon={<MinusOutlined />}
shape={"circle"}
onClick={() => remove(row.name)}
/>
</React.Fragment>
);
}}
/>
</Table>
);
};
Context
export const AppContext = createContext()
export const AppProvider = props => {
const Navigate = useNavigate()
const dateFormat = ['DD-MM-YYYY'];
const StockPick = (values) => {
console.log('Success:', values);
let stockpick = [{
date: moment(values.date).format("DD-MM-YYYY"),
origin: values.origin,
picking_type_id: values.picking_type_id,
location_id: parseInt(values.location_id),
location_dest_id: parseInt(values.location_dest_id),
stock_move_ids: [
{
demand: parseInt(values?.stock_move_ids?.[0]?.demand),
done: parseInt(values?.stock_move_ids?.[0]?.done),
product_uom: parseInt(values?.stock_move_ids?.[0]?.product_uom),
product_tmpl_id: values?.stock_move_ids?.[0]?.product_tmpl_id,
},
],
}];
let params = JSON.stringify(stockpick)
console.log(params)
axios.post('http://127.0.0.1:5000/api/stockpickings', params, { headers })
.then(() => {
Navigate('/')
})
.catch(error => {
if (error.response) {
console.log(error.response);
}
});
};
}
I think this is all I can provide / needed to fix my codings, if there's anything I need to add and or fix, please tell me. Thank you.
Okay after some hours tries
as the comment above, i think all i need to do is just not making the body as dataindex.
from :
<Form.List name="stock_move_ids">
{(stock_move_ids, { add, remove }) => {
return <Stockmovetable stock_move_ids={stock_move_ids} option={option} add={add} remove={remove} dataPupuk={dataPupuk} />;
}}
</Form.List>
to
<Form.List name="stock_move_ids">
{(stock_move, { add, remove }) => {
return <Stockmovetable stock_move_ids={stock_move_ids} option={option} add={add} remove={remove} dataPupuk={dataPupuk} />;
}}
</Form.List>
Thank you very much for the helps!

How to a make dynamic form in React

I'm learning React. My target is to make this object:
"Phones": [
{
"Type": "Mobile",
"Phone_Number": "6546543"
},
{
"Type": "Home",
"Phone_Number": "6546543"
}
]
I did some research and I followed this YouTube video ReactJS - Dynamically Adding Multiple Input Fields.
These values I'll fetch from a form. Th user can keep on adding as many numbers as he wants. My code is:
render() {
return (
<div>
<h1>The Form</h1>
<label>Contact</label>
{this.state.phones.map((phone, index) => {
return (
<div key={index}>
<input onChange={(e) => this.handleChange(e)} value={phone} />
<select>
{this.phoneTypes.map((phoneType, index) => {
return (
<option key={index} value={phoneType}>
{phoneType}
</option>
);
})}
</select>
<button onClick={(e) => this.handleRemove(e)}>Remove </button>
</div>
);
})}
<hr />
<button onClick={(e) => this.addContact(e)}>Add contact</button>
<hr />
<button onClick={(e) => this.handleSubmit(e)}>Submit</button>
</div>
);
}
I'm not pasting the entire code here as I've already created a stackblitz. My code is not working as expected. Please pitch in.
You need to pass index in the handleChange function for input field. I guess you missed that part from video.This will make the input field editable.
<input
onChange={(e) => this.handleChange(e, index)}
value={phone}
/>
For the second part to get the expected object array I have updated some code, please check:
import React, { Component } from 'react';
class Questionnaire extends Component {
state = {
phones: [{ type: '', number: '' }],
};
phoneTypes = ['Mobile', 'Home', 'Office'];
addContact() {
this.setState({ phones: [...this.state.phones, { type: '', number: '' }] });
}
handleChange(e, index) {
this.state.phones[index]['number'] = e.target.value;
this.setState({ phones: this.state.phones });
}
handleRemove(index) {
this.state.phones.splice(index, 1);
console.log(this.state.phones, '$$$');
this.setState({ phones: this.state.phones });
}
handleSubmit(e) {
console.log(this.state, '$$$');
}
render() {
return (
<div>
<h1>The Form</h1>
<label>Contact</label>
{this.state.phones.map((phone, index) => {
return (
<div key={index}>
<input
onChange={(e) => this.handleChange(e, index)}
value={phone.number}
name="number"
/>
<select>
{this.phoneTypes.map((phoneType, index) => {
return (
<option key={index} value={phoneType} name="type">
{phoneType}
</option>
);
})}
</select>
<button onClick={(e) => this.handleRemove(e)}>Remove </button>
</div>
);
})}
<hr />
<button onClick={(e) => this.addContact(e)}>Add contact</button>
<hr />
<button onClick={(e) => this.handleSubmit(e)}>Submit</button>
</div>
);
}
}
export default Questionnaire;
You can use input objects like formik
import { useState } from 'react';
const Component = () => {
const [inputs, setInputs] = useState({ // Initial inputs
email: "",
phoneNumber: "",
});
const handleSubmit = (e) => {
e.preventDefault();
// Do
};
const handleChange = (e) => {
setInputs({...inputs, [e.target.id]: e.target.value});
};
const addInput = () => {
const name = window.prompt("Type a name", "");
setInputs({...inputs, [name]: ""});
};
return (
<form onSubmit={handleSubmit}>
{object.keys(inputs).map((name, i) => {
<input type="text" onChange={handleChange} name={name} value={inputs[name]} />
})}
<button
type="button"
onClick={addInput}
>
Add Input
</button>
</form>
);
}

How to fix update Modal not showing this.state.value

I am trying to create a modal that handles updates, but it's not showing {this. state. value}
state={
name: '',
businessName: '',
show: false,
}
showModal(e) {
if (e) {
this.setState({ show: true });
}
}
showEditModal(e) {
const { user } = this.props.auth;
const email=user.email
axios.get(`/api/v1/auth/userdetails/${email}`)
.then(
(res) => {
console.log(res.data) // res.data actually has data from API
let user = res.data
this.setState ({
id:user.id,
name:user.name,
businessName:user.businessName,
})
this.setState({
show: true,
});
console.log(this.state.name) // i get undefined
},
(err) => {
alert('An error occured! Try refreshing the page.', err);
}
);
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = (e) => {
e.preventDefault();
const {
_id,
name,
businessName,
} = this.state;
const userDetail = {
_id,
name,
businessName,
};
console.log(userDetail);
axios.post(`/api/v1/auth/update/${_id}`, userDetail).then(
(res) => {
Swal.fire({
title: 'Profile ',
text: 'Update successful!',
icon: 'success',
confirmButtonText: 'Ok'
})
},
(err) => {
alert('An error occured! Try submitting the form again.', err);
}
);
};
hideModal = () => {
this.setState({
show: false,
name:'',
businessName:'',
});
};
ModalForm=()=>{
return <div style={{ backgroundColor: 'white' }}>
<Modal
{...this.props}
show={this.state.show}
onHide={this.hideModal}
dialogClassName='custom-modal'
>
<Modal.Header closeButton>
<Modal.Title
id='contained-modal-title-lg '
className='text-center'
>
Update Profile
</Modal.Title>
</Modal.Header>
<Modal.Body className='modal-contentx'>
<Form horizontal onSubmit={this.onSubmit}>
<FormGroup controlId='formHorizontalEmail'>
<Col smOffset={4} sm={6}>
<FormControl
type='Text'
backgroundColor='grey'
placeholder='name'
name='name'
value={this.state.name}
onChange={this.onChange}
/>
</Col>
</FormGroup>
<FormGroup controlId='formHorizontalPassword'>
<Col smOffset={4} sm={6}>
<FormControl
type='text'
placeholder=''
name='businessName'
value={this.state.businessName}
onChange={this.onChange}
/>
</Col>
</FormGroup>
<FormGroup>
<Col smOffset={5} sm={6}>
<Button type='submit' bsStyle='primary'>
Add
</Button>
</Col>
</FormGroup>
</Form>
</Modal.Body>
</Modal>
</div>
<ButtonGroup>
<Button className="btn-fill" color="primary" type="submit">
Save
</Button>
<Button className="btn-fill" onClick={(e) => this.showEditModal(e)}>
Update
</Button>
</ButtonGroup>
}
render(){
return (
<div>
// Add form is placed here
</div>
<div>
// modal form is placed here
{this.ModalForm()}
</div>
)
}
the modal comes up onClick, but fails to show any value. When i do console.log(this.state.name) for instance i get undefined?!
I need the Modal to be populated with the value from the state. The response object from the console contains the data that i am using to update the state through setState().
i guess something is off though, but cant figure it out

is there any way to disable send button until message got typed in the message field without onchange method in reactjs

I'm new to react, My objective is to disable send button until message got typed in the message field or to show some popup without writing anything in textfield and clicking on send button. For Disabling - I've tried by giving onChange method but due to onchange method input field is getting laggy. That's why i'm using Id. Can anyone suggest me any way of disabling the button ?
Here is the code:
class Data extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{ isSender: true, content: "hello" },
{ isSender: false, content: "hello1" },
{ isSender: true, content: "hello2" },
{ isSender: false, content: "hello3" },
{ isSender: true, content: "hello4" },
{ isSender: false, content: "hello5" },
{ isSender: true, content: "hello6" },
{ isSender: false, content: "hello7" }
],
msg: ""
};
}
componentDidMount() {
this.scrollToBottom();
}
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth" });
};
componentDidUpdate() {
this.scrollToBottom();
}
handleSubmit = e => {
e.preventDefault();
let text = document.getElementById("text").value;
console.log(text);
};
render() {
const { classes } = this.props;
return (
<Card>
<CardHeader
avatar={<Avatar aria-label="recipe">S</Avatar>}
title={
<>
<InputBase placeholder="Search Google Maps" margin="normal" />
<IconButton type="submit" aria-label="search">
<SearchIcon />
</IconButton>
</>
}
/>
<Divider />
<CardContent
style={{ overflow: "scroll" }}
className={classes.contentHeight}
id="chatList"
>
<div>
<Message isSender content="Hello" />
{this.state.data.map(item => {
if (item.isSender) {
return <Message isSender content={item.content} />;
}
return <Message content={item.content} />;
})}
</div>
<div
style={{ float: "left", clear: "both" }}
ref={el => {
this.messagesEnd = el;
}}
/>
</CardContent>
<Divider />
<CardActions>
<Paper className={classes.contentPaper}>
<Input
margin="dense"
className={classes.input}
placeholder="Enter a Message"
disableUnderline
name="msg"
id="text"
/>
<Button onClick={this.handleSubmit}>Send</Button>
</Paper>
</CardActions>
</Card>
);
}
}
Either the send button needs to disable or while clicking on the send button without typing anything in input field - it should show snackbar at the top of the textfield as "Enter something".
Can anyone please help me in this?
Here is the whole code:
You should update state on onChange for input
<Input
margin="dense"
className={classes.input}
placeholder="Enter a Message"
disableUnderline
name="msg"
id="text"
onChange={e => this.setState({ msg: e.target.value })}
/>
And disable attribute to Button
<Button onClick={this.handleSubmit} disabled={!this.state.msg.length}>
Send
</Button>
Try to avoid document.getElementById("text").value in react, it's better to use state or ref

react is editing all array objects instead of just one array object

Currently a user can enter first, lastname, and employee id. When it submits it renders an iteration of employees with the first, last, and employee id.
The problem is when you click edit, it edits the data but it will edit all of the fields for every object in the employees iteration.
How can I fix the code so that it will edit just that particular object within that iteration.
Home component
........
class Login extends Component {
constructor(props) {
super(props);
this.state = {
activeTab: '3',
firstName: '',
lastName: '',
employeeID: '',
employees: [],
Edit: false,
updatedFirst: '',
updatedLast:'',
updatedEmployeeID: ''
};
}
toggle = (tab) => {
if(this.state.activeTab !== tab){
this.setState({
activeTab: tab
})
}
}
onSubmit = (e) => {
e.preventDefault();
const {firstName, lastName, employeeID} = this.state
const ourForm ={
firstName: firstName,
lastName: lastName,
employeeID: employeeID,
// we need an id to so that it can be edited properly
}
this.setState({
employees: [...this.state.employees,ourForm]
}, () => {
console.log(this.state.employees)
})
}
onChange = (e) => {
e.preventDefault()
// e.preventDefault();
this.setState({
[e.target.name]: e.target.value,
});
}
updatedChange = (e) => {
e.preventDefault()
// e.preventDefault();
this.setState({
[e.target.name]: e.target.value,
});
}
onEdit = (e) => {
e.preventDefault();
this.setState({
Edit: !this.state.Edit
})
}
onReset = (e) => {
e.preventDefault();
this.setState({
firstName: '',
lastName: '',
employeeID: ''
})
}
render(){
return (
......
<MyForm
onSubmit={this.onSubmit}
onChange={this.onChange}
onReset={this.onReset}
firstName={this.state.firstName}
lastName={this.state.lastName}
employeeID={this.state.employeeID}
/>
</Col>
</Row>
</TabPane>
</TabContent>
</Container>
<List
employees={this.state.employees}
Edit={this.state.Edit}
onEdit ={this.onEdit}
onChange={this.onChange}
updatedEmployeeID={this.state.updatedEmployeeID}
updatedFirst={this.state.updatedFirst}
updatedLast={this.state.updatedLast}
/>
</div>
);
}
}
export default Login;
Form.js
import React, {Component} from 'react';
import { Col, Form, FormGroup, Label, Input, Button } from 'reactstrap';
const MyForm = (props) => {
return(
<Form style={{ margin: '30px 0px'}}>
<FormGroup row>
<Label for="firstName" sm={2} size="sm">First Name:</Label>
<Col sm={10}>
<Input type="text" onChange={props.onChange} value={props.firstName} name="firstName" id="exampleEmail" placeholder="Enter First Name"/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="lastName" sm={2} size="sm">Last Name:</Label>
<Col sm={10}>
<Input type="text" onChange={props.onChange} value={props.lastName} name="lastName" id="exampleEmail2" placeholder="Enter Last Name" />
</Col>
</FormGroup>
<FormGroup row>
<Label for="Employee ID" sm={2} size="sm">Employee ID:</Label>
<Col sm={5}>
<Input type="text" onChange={props.onChange} value={props.employeeID} name="employeeID" id="exampleEmail2" placeholder="Enter Employee ID" />
</Col>
</FormGroup>
<FormGroup row>
<Col sm={12}>
<div className="float-right">
<Button onClick={props.onSubmit} size="lg" style={{ margin: '0px 5px'}} color="secondary">Add</Button>
<Button onClick={props.onReset} size="lg" style={{ margin: '0px 5px'}}color="warning">Reset</Button>
</div>
</Col>
</FormGroup>
<hr></hr>
<FormGroup row>
<Col sm={4}>
<Input type="text" name="search" id="exampleEmail2" placeholder="Search" />
</Col>
<Col sm={8}>
<Label for="sort" sm={2} size="sm">Sort:</Label>
<Button onClick={props.onSubmit} size="lg" style={{ margin: '0px 5px'}} color="secondary">First Name</Button>
<Button onClick={props.onSubmit} size="lg" style={{ margin: '0px 5px'}} color="secondary">Last Name</Button>
<Button onClick={props.onSubmit} size="lg" style={{ margin: '0px 5px'}} color="secondary">ID</Button>
</Col>
</FormGroup>
</Form>
)
}
export default MyForm;
List component
import React, {Component, Fragment} from 'react';
import { Col, Form, FormGroup, Label, Input, Button } from 'reactstrap';
const List = (props) => {
return(
<Fragment>
{props.employees.map( (item, i) => (
<div style={{ margin: '40px 0px'}} key={i}>
<hr style={{ border:'1px dashed #000'}}></hr>
<div className="float-right">
<Button onClick={props.onEdit} size="lg" style={{ margin: '0px 5px'}} color="secondary">{props.Edit ? 'Save': 'Edit'}</Button>
<Button size="lg" style={{ margin: '0px 5px'}}color="secondary">Delete</Button>
</div>
<FormGroup row>
<Col sm={5}>
{props.Edit ? (
<Input type="text" onChange={props.onChange} value={ props.updatedFirst ? props.updatedFirst : item.firstName } name="updatedFirst" placeholder="Enter First Name"/>
):(
<div>
{props.updatedFirst ? props.updatedFirst : item.firstName }
</div>
)}
</Col>
</FormGroup>
<FormGroup row>
<Col sm={5}>
{props.Edit ? (
<Input type="text" onChange={props.onChange} value={ props.updatedEmployeeID ? props.updatedEmployeeID : item.employeeID} name="updatedEmployeeID" placeholder="Enter EmployeeID"/>
):(
<div>
{props.updatedEmployeeID ? props.updatedEmployeeID : item.employeeID}
</div>
)}
</Col>
</FormGroup>
<FormGroup row>
<Col sm={5}>
{props.Edit ? (
<Input type="text" onChange={props.onChange} value={ props.updatedLast ? props.updatedLast: item.lastName} name="updatedLast" placeholder="Enter Last Name"/>
):(
<div>
{props.updatedLast ? props.updatedLast : item.lastName}
</div>
)}
</Col>
</FormGroup>
</div>
))}
</Fragment>
)
}
export default List;
The following example shows how to pass a handler and set the state accordingly.
For good measure I separated the logic and the presentation, the presentational components are pure components using React.memo.
//A container should only contain the logic
class EmployeesContainer extends React.Component {
state = {
employees: [{ name: '' }, { name: '' }, { name: '' }],
};
//define what needs to happen if you click edit on an
// employee
onEdit = index => {
//edit will be called with the index of the employee
// the Employees component owns the list of employees
// so it will have to make changes to it
this.setState({
employees: this.state.employees.map((employee, i) =>
i === index ? { ...employee, edit: true } : employee
),
});
};
//Same idea as onEdit, index needs to be passed to indicate
// what employee needs to be changed
onChange = (index, e) => {
this.setState({
employees: this.state.employees.map((employee, i) =>
i === index
? { ...employee, name: e.target.value }
: employee
),
});
};
render() {
return (
<Employees
employees={this.state.employees}
onEdit={this.onEdit}
onChange={this.onChange}
/>
);
}
}
//The Employees presentational component, contains the jsx
// you can make it a pure component by using React.memo
const Employees = React.memo(
({ employees, onEdit, onChange }) => (
<div>
{employees.map((employee, index) => (
<EmployeeContainer
key={index}
index={index}
employee={employee}
onEdit={onEdit}
onChange={onChange}
/>
))}
</div>
)
);
//Make this a container as well because it does more
// than only produce jsx
class EmployeeContainer extends React.Component {
state = {};
//create onChange and onEdit only when index changes
// this will prevent unnecessary renders
static getDerivedStateFromProps(props, state) {
const { index, onChange, onEdit } = props;
if (state.index !== index) {
return {
index,
onChange: e => onChange(index, e),
onEdit: () => onEdit(index),
};
}
return null;
}
render() {
const { employee } = this.props;
const { onChange, onEdit } = this.state;
return (
<Employee
employee={employee}
onChange={onChange}
onEdit={onEdit}
/>
);
}
}
//presentational component, is also pure component
const Employee = React.memo(
({ employee, onChange, onEdit }) => (
<div>
{employee.edit ? (
<input
type="text"
value={employee.name}
onChange={onChange}
/>
) : (
<button onClick={onEdit}>edit</button>
)}
</div>
)
);
I don’t think onSubmit is updating employees correctly. You shouldn’t use this.state inside setState.
this.state inside setState ReactJS
Try this..
this.setState(prevState => ({
employees: [...prevState.employees, ourForm]
}, () => {
console.log(this.state.employees)
}))

Resources