I'm passing data from am AddItem modal in react to a table in the NewInvoice component. The data is being populated to the table successfully but modal does not close after clicking the save button. Kindly assist on what i could be missing on this.
NewInvoice.js
const [itemOpen, setitemOpen] = useState(false);
<div className="new-invoice-client">
<FormDataTable itemOpen={itemOpen}/>
</div>
<div
className="new-item-links"
style={{ marginLeft: "35px", marginTop: "35px" }}
>
<Button onClick={() => setitemOpen(true)}>
<BsPlus />
Add an Item
{itemOpen && <AddItem setitemOpen={setitemOpen} />}
</Button>
</div>
The <FormInvoiceTable/> is passed to the NewInvoice parent component as shown below.
FormInvoieTable.js
function FormDataTable(props) {
const [tableData, setTableData] = useState([]);
// console.log(tableData)
const tableRows = tableData.map((value, index) => {
return (
<tr key={index}>
<td>{value.item}</td>
<td>{value.amount}</td>
<td>{value.rate}</td>
<td>{value.quantity}</td>
<td>{value.description}</td>
</tr>
);
});
const addRows = (data) => {
const totalData = tableData.length;
data.id = totalData + 1;
const updatedtableData = [...tableData];
updatedtableData.push(data);
setTableData(updatedtableData);
};
return (
<React.Fragment>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Description</th>
<th>Qty</th>
<th>Rate</th>
<th>Amount</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
<AddItem func={addRows}/>}
</React.Fragment>
);
}
AddItem.js Modal
function AddItem(props) {
const [item, setItem] = useState("");
const [amount, setAmount] = useState("");
const [rate, setRate] = useState("");
const [quantity, setQuantity] = useState("");
const [description, setDescription] = useState("");
const clearState = () => {
setItem("");
setAmount("");
setRate("");
setQuantity("");
setDescription("");
};
const handleSubmit = (event) => {
event.preventDefault();
const formInputData = {
item,
amount,
rate,
quantity,
description,
};
props.func(formInputData);
// clearState();
props.setitemOpen(false)
};
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title">
<h1>New Item</h1>
</div>
<div className="modal-form-container">
<form className="register-form">
<input
className="register-input"
name="item"
onChange={(e) => setItem(e.target.value)}
value={item}
placeholder="Item"
/>
<input
className="register-input"
name="amount"
value={amount}
placeholder="Amount"
onChange={(e) => setAmount(e.target.value)}
/>
<input
className="register-input"
placeholder="Rate"
name="rate"
value={rate}
onChange={(e) => setRate(e.target.value)}
/>
<input
className="register-input"
name="quantity"
placeholder="Quantity"
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
/>
<input
className="register-input"
style={{ width: "600px", height: "80px" }}
type="text"
value={description}
placeholder="Description"
onChange={(e) => setDescription(e.target.value)}
/>
<div className="modal-buttons" style={{ justifyContent: "center" }}>
<button onClick={handleSubmit}>Save</button>
<button onClick={() => props.setitemOpen(false)}>cancel</button>
</div>
</form>
</div>
</div>
</div>
);
}
Your are creating component <AddItem/> two times.
When you create it in FormDataTable component you don't pass it prop setitemOpen. You are passing only addRows function as a prop :
<AddItem func={addRows}/>
One solution would be to pass setitemOpen={setitemOpen} prop to FormDataTable component and call it in addRow method with argument false. Also, remove AddItem component from NewInvoice component and create it only in FormDataTable component based on itemOpen
Here is code snippet:
NewInvoice.jsx
import React from "react";
import FormDataTable from "./FormInvoieTable";
import { useState } from "react";
import Button from "#mui/material/Button";
export default function NewInvoice(props) {
const [itemOpen, setitemOpen] = useState(false);
return (
<>
<div className="new-invoice-client">
<FormDataTable itemOpen={itemOpen} setitemOpen={setitemOpen} />
</div>
<div
className="new-item-links"
style={{ marginLeft: "35px", marginTop: "35px" }}
>
<Button onClick={() => setitemOpen(true)}>Add an Item</Button>
</div>
</>
);
}
Then in FormDataTable component, modify addRows method like this:
FormDataTable.jsx
import React from "react";
import AddItem from "./AddItem";
import { useState } from "react";
export default function FormDataTable(props) {
const [tableData, setTableData] = useState([]);
const { itemOpen } = props;
const tableRows = tableData.map((value, index) => {
return (
<tr key={index}>
<td>{value.item}</td>
<td>{value.amount}</td>
<td>{value.rate}</td>
<td>{value.quantity}</td>
<td>{value.description}</td>
</tr>
);
});
const addRows = (data) => {
const totalData = tableData.length;
data.id = totalData + 1;
const updatedtableData = [...tableData];
updatedtableData.push(data);
setTableData(updatedtableData);
props.setitemOpen(false);
};
return (
<React.Fragment>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Description</th>
<th>Qty</th>
<th>Rate</th>
<th>Amount</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
{itemOpen && <AddItem func={addRows} />}
</React.Fragment>
);
}
AddItem.jsx
import React from "react";
import { useState } from "react";
export default function AddItem(props) {
const [item, setItem] = useState("");
const [amount, setAmount] = useState("");
const [rate, setRate] = useState("");
const [quantity, setQuantity] = useState("");
const [description, setDescription] = useState("");
console.log(props);
const clearState = () => {
setItem("");
setAmount("");
setRate("");
setQuantity("");
setDescription("");
};
const handleSubmit = (event) => {
event.preventDefault();
const formInputData = {
item,
amount,
rate,
quantity,
description,
};
props.func(formInputData);
// clearState();
};
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title">
<h1>New Item</h1>
</div>
<div className="modal-form-container">
<form className="register-form">
<input
className="register-input"
name="item"
onChange={(e) => setItem(e.target.value)}
value={item}
placeholder="Item"
/>
<input
className="register-input"
name="amount"
value={amount}
placeholder="Amount"
onChange={(e) => setAmount(e.target.value)}
/>
<input
className="register-input"
placeholder="Rate"
name="rate"
value={rate}
onChange={(e) => setRate(e.target.value)}
/>
<input
className="register-input"
name="quantity"
placeholder="Quantity"
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
/>
<input
className="register-input"
style={{ width: "600px", height: "80px" }}
type="text"
value={description}
placeholder="Description"
onChange={(e) => setDescription(e.target.value)}
/>
<div className="modal-buttons" style={{ justifyContent: "center" }}>
<button onClick={handleSubmit}>Save</button>
<button onClick={() => props.setitemOpen(false)}>cancel</button>
</div>
</form>
</div>
</div>
</div>
);
}
Related
I have two fields and a button. I want to render input values on the click of a button. Can you guys please tell me how to do it?
function Home() {
const [name, setName] = useState('')
const [age, setAge] = useState(0)
const submitForm = () => {
console.log(name, age)
}
return (
<div>
<div>
<label htmlFor="name">Name:</label>
<input type="text" value={name} onChange={e => setName(e.target.value)} />
</div>
<div>
<label htmlFor="age">age:</label>
<input type="number" value={age} onChange={e => setAge(e.target.value)} />
</div>
<button onClick={submitForm}>Submit</button>
<h1>render "name" gere</h1>
<h2>render "age" gere</h>
</div>
)
}
export default Home
You can add a state to track the display state, as
const [visible, setVisible] = useState(false)
Alter it in form submit as:
const submitForm = () => {
setVisible(true)
}
And render it as:
{visible && <><h1>render {name} gere</h1>
<h2>render {age} gere</h2> </>}
I fix it like this.
function Home() {
const [name, setName] = useState('')
const [age, setAge] = useState(0)
const [data, setData] = useState({})
const submitForm = () => {
setData({name, age})
}
return (
<div>
<div>
<label htmlFor="name">Name:</label>
<input type="text" value={name} onChange={e => setName(e.target.value)} />
</div>
<div>
<label htmlFor="age">age:</label>
<input type="number" value={age} onChange={e => setAge(e.target.value)} />
</div>
<button onClick={submitForm}>Submit</button>
<h1>{data.name}</h1>
<h2>{data.age}</h2>
</div>
)
}
export default Home
Try this and see if it helps.
function Home() {
const {register, handleSubmit} = useForm()
const onSubmit = (data) => {
console.log(data)
}
return (
<form onSubmit = {handleSubmit(onSubmit)}>
<div>
<div>
<label htmlFor="name">Name:</label>
<input type="text" value={name} onChange={e => setName(e.target.value)} />
</div>
<div>
<label htmlFor="age">age:</label>
<input type="number" value={age} onChange={e => setAge(e.target.value)} />
</div>
<button onSubmit={submitForm}>Submit</button>
<h1>render "name" gere</h1>
<h2>render "age" gere</h>
</div>
<form/>
);
}
As you can see in the below picture when i came to this page it look like this and it's perfectly fine as i want
but when i upload in image (using dropzoneArea) material UI it become look like this and all the drop down menu will be in single line and also you will see submit button also changed
uploadProduct.js
import React, { useState,useEffect } from "react";
import { useHistory, useLocation } from "react-router-dom";
import {
Typography,
Grid,
Button,
FormGroup,
TextField,
Select,
MenuItem,
InputLabel,
FormControl,
InputAdornment,
Input,
} from "#mui/material";
import "./styles.css";
import FileUpload from "../../utils/FileUpload";
import Axios from "axios";
import MuiPhoneNumber from "material-ui-phone-number";
import decode from "jwt-decode";
export const UploadProduct = (props) => {
const location = useLocation();
const history = useHistory();
const [Token_Id, setToken_Id] = useState(localStorage.getItem("token"))
const [Title, setTitle] = useState("");
const [userId, setuserId] = useState(0);
const [Description, setDescription] = useState("");
const [Price, setPrice] = useState();
const [Category, setCategory] = useState("");
const [perGiven, setperGiven] = useState("");
const [Phone, setPhone] = useState("");
const [Address, setAddress] = useState("");
const [Name, setName] = useState("")
const [Images, setImages] = useState([]);
const handleLogout = () => {
localStorage.removeItem("token");
history.push("/");
setName("");
props.showAlert("Logout Successfully", "success");
};
useEffect(() => {
const token = Token_Id;
if (token) {
const { exp, name, id } = decode(token);
setuserId(id)
setName(name);
if (Date.now() >= exp * 1000) {
handleLogout();
}
}
setToken_Id(localStorage.getItem("token"));
}, [location]);
const updateImages = (newImages) => {
setImages(newImages);
};
const onSubmit = (event) => {
event.preventDefault();
if (
!userId ||
!Name ||
!Title ||
!Description ||
!Price ||
!Category ||
!perGiven ||
!Phone ||
!Address ||
!Images
) {
return alert("fill all the fields first!");
}
const variables = {
userId: userId,
userName: Name,
title: Title,
description: Description,
category: Category,
price: Price,
rentType: perGiven,
images: Images,
phoneNumber: Phone,
address: Address,
};
Axios.post("/product/uploadProduct", variables).then((response) => {
if (response.data.success) {
alert("Product Successfully Uploaded");
history.push("/");
} else {
alert("Failed to upload Product");
}
});
};
return (
<div
className="parentDiv"
style={{marginTop: "70px", paddingBottom: "10px" }}
>
<div style={{ maxWidth: "700px", margin: "2rem auto" }}>
<div style={{ textAlign: "center", marginBottom: "2rem" }}>
<Typography variant="h4">Anything for rent?</Typography>
</div>
<FormGroup>
{/* DropZone */}
<FileUpload refreshFunction={updateImages} />
<br />
<TextField
variant="standard"
required
fullWidth
id="title"
label="AD TITLE"
name="title"
value={Title}
autoFocus
onChange={(e) => setTitle(e.target.value)}
/>
<br />
<TextField
variant="standard"
required
fullWidth
id="description"
label="DESCRIPTION"
name="description"
value={Description}
onChange={(e) => setDescription(e.target.value)}
/>
<br />
<FormControl variant="standard" sx={{ m: 0, minWidth: 120 }}>
<InputLabel id="demo-simple-select-label">
CHOOSE CATEGORY
</InputLabel>
<Select
labelId="demo-simple-select-label"
label="CHOOSE CATEGORY"
name="category"
onChange={(e) => {
setCategory(e.target.value);
}}
className="input"
style={{display: "flex", alignItems: "center"}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value="Tools">Tools</MenuItem>
<MenuItem value="Apparels">Apparels</MenuItem>
<MenuItem value="Vehicles">Vehicles</MenuItem>
<MenuItem value="Equipments">Equipments</MenuItem>
<MenuItem value="Footwear">Footwear</MenuItem>
</Select>
</FormControl>
<br />
<MuiPhoneNumber
className="my-2"
label="PHONE NUMBER"
variant="standard"
value={Phone}
defaultCountry={"pk"}
onChange={setPhone}
/>
<br />
<Grid container className="my-1">
<Grid item>
<InputLabel htmlFor="standard-adornment-amount">
SET A PRICE
</InputLabel>
<Input
id="standard-adornment-amount"
required={true}
value={Price}
onChange={(e) => {
setPrice(e.target.value);
}}
startAdornment={
<InputAdornment position="start">Rs</InputAdornment>
}
/>
{/* <TextField required fullWidth id="price" label="Price" name="price" value={Price} onChange={(e) => {setPrice(e.target.value)}} variant="standard" /> */}
</Grid>
<Grid
item
className="mx-2"
alignItems="stretch"
style={{ display: "flex" }}
>
<FormControl
className="my-1"
variant="standard"
sx={{ m: 2, minWidth: 150 }}
>
<InputLabel id="demo-simple-select-standard-label">
Rent type
</InputLabel>
<Select
labelId="demo-simple-select-standard-label"
id="demo-simple-select-standard"
value={perGiven}
onChange={(e) => {
setperGiven(e.target.value);
}}
label="rent type"
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value="Day">Day</MenuItem>
<MenuItem value="Week">Week</MenuItem>
<MenuItem value="Month">Month</MenuItem>
</Select>
</FormControl>
</Grid>
</Grid>
<TextField
className="my-2"
variant="standard"
required
fullWidth
id="address"
label="ADDRESS"
name="address"
value={Address}
onChange={(e) => setAddress(e.target.value)}
/>
<Button className="my-3" variant="contained" onClick={onSubmit}>
Submit
</Button>
</FormGroup>
</div>
</div>
);
};
FileUpload.js
import React, { useState } from "react";
import { DropzoneArea } from "material-ui-dropzone";
import Axios from "axios";
function FileUpload(props) {
const [Images, setImages] = useState([]);
const onDrop = (files) => {
let formData = new FormData();
const config = {
header: { "content-type": "multipart/form-data" },
};
formData.append("file", files[0]);
//save the Image we chose inside the Node Server
Axios.post("/product/uploadImage", formData, config).then((response) => {
if (response.data.success) {
setImages([...Images, response.data.image]);
props.refreshFunction([...Images, response.data.image]);
} else {
alert("Failed to save the Image in Server");
}
});
};
const onDelete = (image) => {
const currentIndex = Images.indexOf(image);
let newImages = [...Images];
newImages.splice(currentIndex, 1);
setImages(newImages);
props.refreshFunction(newImages);
};
return (
<div style={{ display: "flex", justifyContent: "space-between" }}>
<DropzoneArea
onDrop={onDrop}
multiple={false}
maxSize={5000000}
showPreviewsInDropzone={false}
>
{({ getRootProps, getInputProps }) => (
<div
style={{
width: "300px",
height: "240px",
border: "1px solid lightgray",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
{...getRootProps()}
>
<input {...getInputProps()} />
</div>
)}
</DropzoneArea>
<div
style={{
display: "flex",
marginLeft: "10px",
width: "350px",
height: "250px",
overflowX: "scroll",
}}
>
{Images.map((image, index) => (
<div onClick={() => onDelete(image)}>
<img
style={{ minWidth: "200px", width: "220px", height: "230px" }}
src={`http://localhost:5000/${image}`}
alt={`productImg-${index}`}
/>
</div>
))}
</div>
</div>
);
}
export default FileUpload;
As you can see in the UploadProduct.js i called the FileUpload component for uploading the files.
If you find any error or bug please let me know and any suggestion will be helpfull
TIA
So, I have this appointments array coming in from its parent component. This component should map over the array, and then return a div for each item that occurs at a date later than today. Then, when the user clicks the "confirm" button it should re-render the list and remove that item that was just clicked from the list of rendered divs.
The problem is when it re-renders, I get the same "appointments.map() is not a function" error. If I click refresh the component renders as expected with the div that was clicked on removed from the list.
I can't seem to figure out why, as this component shouldn't even load unless the appointments array has a length (as it states in the parent component).
This is the parent component:
import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { getAppointments } from '../../../actions/appointment'
import ConfirmAppointment from '../Appointments/ConfirmAppointment'
const Dashboard = ({user}) => {
const dispatch = useDispatch()
useEffect(() => {
//get appointment data
dispatch(getAppointments(user?.result._id))
}, [dispatch])
const appointments = useSelector((state)=>state?.usersReducer?.appointment)
return (
<>
<div>
<h3>Welcome {user?.result?.firstName}! :D</h3>
{/* <Link to='/bookappointment'>
<button className="ui button" style={{backgroundColor: '#adad85'}}>Book an appointment</button>
</Link> */}
<Link to="/healthhistory/update" >
<button className="ui button" style={{backgroundColor: '#adad85'}}>Update Health History</button>
</Link>
<Link to="/dashboard/receipts">
<button className="ui button" style={{backgroundColor: '#adad85'}}>View Appointment Receipts</button>
</Link>
{appointments?.length === 0 ? (
<div>Loading ...</div>
) : (
<ConfirmAppointment user={user} appointments={appointments} />
)
}
</div>
</>
)
}
export default Dashboard
And this is the component with the .map function:
import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { confirmAppointment } from '../../../actions/appointment'
const ConfirmAppointment = ({user, appointments}) => {
const dispatch = useDispatch()
const { _id } = user?.result
const today = new Date()
const [reasonForMassage, setReasonForMassage] = useState('')
const [treatmentConsent, setTreatmentConsent] = useState(false)
const [glutes, setGlutes] = useState(false)
const [chest, setChest] = useState(false)
const [abdomen, setAbdomen] = useState(false)
const [innerThighs, setInnerThighs] = useState(false)
const [areasToAvoid, setAreasToAvoid] = useState('')
const formData = {
reasonForMassage,
consents: {
treatmentConsent,
glutes,
chest,
abdomen,
innerThighs,
areasToAvoid
}
}
const handleSubmit = (e, appointmentId) => {
e.preventDefault()
setTreatmentConsent(true)
//update appointment with the appointment id
dispatch(confirmAppointment(_id, appointmentId, formData))
clear()
}
const clear = () => {
setReasonForMassage('')
setGlutes(false)
setChest(false)
setAbdomen(false)
setInnerThighs(false)
setAreasToAvoid(false)
}
return (
appointments?.length === 0 ? (
<div>
No upcoming appointments
</div>
) : (
<div style={{marginTop: '3em'}}>
<h4>Upcoming Appointments</h4>
{appointments && appointments?.map((appointment) => (
new Date(appointment?.date) >= today && appointment?.consents?.treatmentConsent !== true ? (
<div style={{marginBottom: '3em'}} key={appointment._id} >
<table className="ui table">
<thead>
<tr>
<th>Date</th>
<th>Time</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
<tr>
<td>{appointment?.date}</td>
<td>{appointment?.time}</td>
<td>{appointment?.duration}</td>
</tr>
</tbody>
</table>
<form className="ui form" onSubmit={(e)=>handleSubmit(e, appointment?._id)} >
<div className="ui fields">
<div className="ui field">
<label>Reason for booking massage:</label>
<input type="text" value={reasonForMassage} onChange={(e)=>setReasonForMassage(e.target.value)}/>
</div>
<div className="ui field">
<h5>I give consent to massage the following areas:</h5>
<div>
<input type="checkbox" value={glutes} onChange={(e)=>setGlutes(e.target.checked)} />
<label>Glutes</label>
<input type="checkbox" value={abdomen} onChange={(e)=>setAbdomen(e.target.checked)} />
<label>Abdomen</label>
<input type="checkbox" value={chest} onChange={(e)=>setChest(e.target.checked)} />
<label>Chest</label>
<input type="checkbox" value={innerThighs} onChange={(e)=>setInnerThighs(e.target.checked)} />
<label>Inner thighs</label>
</div>
</div>
<div className="ui field">
<label>Are there any other areas you would not like to be massaged?</label>
<input type="text" value={areasToAvoid} onChange={(e)=>setAreasToAvoid(e.target.value)} />
</div>
</div>
<button type="submit" className="ui button">Confirm Appointment</button>
</form>
</div>
) : (
<div></div>
)
))}
</div>
)
)
}
export default ConfirmAppointment
I'm learning React and atm i'm making a crud App for Employee Data. Now the problem I'm having is that when i click on Add New button or Update button my component loads for respective features but my old component which is my Table of Data for all my employees stays open along with the new component. I want my Table of data to be disabled or hidden until my New Employee is added or old employee is updated on submission but i'm unable to do that... I made the AddNew.js for adding new employees, UpdateMember.js for updating old employees and then imported these components in my Table.js file which is then returned in the App.js component
The update component loads right on the spot of the update button itself which is another problem for me right now.
almost same is happening with Update even worse with this one
AddNew.js
function AddNew() {
const [list, setList] = useState(null);
const [Name, setName] = useState("");
const [Department, setDepartment] = useState("");
const [Salary, setSalary] = useState("");
const Data = {
name: Name,
department: Department,
salary: Salary,
};
const PostData = () => (event) => {
let header = new Headers();
header.append("Content-Type", "application/json");
// header.append("Accept", "application/json");
//
return (
fetch(PostUrl, {
method: "POST",
headers: header,
body: JSON.stringify(Data),
})
///
.then(() => {
fetch(BaseUrl, { method: "GET", headers: header })
//
.then((response) => response.json())
.then((result) => {
console.log(result);
setList(result);
});
})
);
};
return (
<div>
<form onSubmit={PostData}>
<h2>Add New Members</h2>
<span>* All fields are required</span>
<div className="outerDiv">
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="name"
placeholder="Name"
onChange={(event) => setName(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Department"
placeholder="Department"
onChange={(event) => setDepartment(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Salary"
placeholder="Salary"
onChange={(event) => setSalary(event.target.value)}
/>
</div>
<input className="btn btn-primary" type="submit" value="Save" />
</div>
</form>
</div>
);
}
export default AddNew;
UpdateMember.js
const UpdateRow = () => (event) => {
const PutData = {
name: Name,
department: Department,
salary: Salary,
};
console.log("Update Clicked");
let header = new Headers();
header.append("Content-Type", "application/json");
header.append("Accept", "application/json");
fetch(PutUrl, {
method: "PUT",
headers: header,
body: JSON.stringify(PutData),
})
.then((response) => response.json())
.then((response) => console.log(response))
.then(() => {
fetch(BaseUrl, { method: "GET", headers: header })
.then((res) => res.json())
.then((result) => {
setList(result);
});
});
};
return (
<div>
<form onSubmit={UpdateRow}>
<span className="text">* All fields are required</span>
<hr />
<div>
<h2>Update Information</h2>
<div className="outerDiv">
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="name"
placeholder="Name"
onChange={(event) => setName(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Department"
placeholder="Department"
onChange={(event) => setDepartment(event.target.value)}
/>
</div>
<div className="innerDiv">
<input
type="text"
autoComplete="off"
name="Salary"
placeholder="Salary"
onChange={(event) => setSalary(event.target.value)}
/>
</div>
<button
style={{ float: "right" }}
className="button btn-warning"
type="submit"
>
Update
</button>
</div>
</div>
</form>
</div>
);
}
export default UpdateMember;
Table.js
function Table() {
//
const [list, setList] = useState([]);
useEffect(() => {
let mounted = true;
getList().then((items) => {
if (mounted) {
setList(items);
}
});
return () => (mounted = false);
}, []);
//
const DeleteRow = (id) => (event) => {
let header = new Headers();
header.append("Content-Type", "application/json");
header.append("Accept", "application/json");
return fetch(DeleteUrl + id, { method: "DELETE", headers: header }).then(
() => {
fetch(BaseUrl, { method: "GET", headers: header })
.then((response) => response.json())
.then((result) => {
console.log(result);
setList(result);
});
}
);
};
//
return (
<div>
<h1>Employees Data</h1>
<Router>
<Link to="/Addnew" target="_blank">
<button
style={{ float: "right" }}
className="button btn-primary LinkButton"
>
Add New
</button>
</Link>
<Route path="/AddNew">
<AddNew />
</Route>
</Router>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Department</th>
<th>Salary</th>
<th>Actions</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{list.map((item) => (
<tr key={item.id}>
<td>
<center>{item.id}</center>
</td>
<td>
<center>{item.name}</center>
</td>
<td>
<center>{item.department}</center>
</td>
<td>
<center>{item.salary}</center>
</td>
<td>
<center>
<button
// key={item.id}
className="button btn-danger"
onClick={DeleteRow(item.id)}
>
Delete
</button>
</center>
</td>
<td>
<center>
<Router>
<Link to="/UpdateMember">
<button className="button btn-warning LinkButton">
Update
</button>
</Link>
<Switch>
<Route path="/UpdateMember">
<UpdateMember id={item.id} />
</Route>
</Switch>
</Router>
</center>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Table;
App.js
function App() {
return (
<Table />
);
}
export default App;
I think that some conditional rendering could help you out with the problem.
Check it out here.
You can create a new variable called isLoading which will be set to true when you start a fetch and false after the fetch has finished. Then after that you can use it to check if isLoading is true, if it is true, do not show the table (conditional rendering)
And another suggestion would be creating a spinner to show when loading is true and hide when it is false, so that the user will know that it is loading.
Hope you guys are fine.
I have the next code for dynamically show the quantity of each selected product
import React, { useState, useEffect } from 'react';
import db from '../firebase';
//const Swal = window.Swal;
const NewSale = () => {
const [products, setProducts] = useState([]);
const [selectedProducts, setSelectedProducts] = useState([]);
useEffect(() => {
if(products.length === 0){
db.collection('products').get().then((querySnapshot) => {
const docs = [];
querySnapshot.forEach((doc) => {
docs.push({
id: doc.id,
...doc.data()
});
});
docs.sort((a, b)=> a.name.localeCompare(b.name));
setProducts(docs);
});
}
});
const handleSelectChange = (e) => {
const value = e.target.value;
if(value){
const selectedProduct = products.filter(item => item.id === value)[0];
setSelectedProducts(selectedProducts => [...selectedProducts, {
id: value,
name: selectedProduct.name,
quantity: 1
}]);
}
}
const handleRangeChange = (target, index) => {
const currentValue = parseInt(target.value);
let currentArrayValue = selectedProducts;
currentArrayValue[index].quantity = currentValue;
setSelectedProducts(currentArrayValue);
}
const handleCancelButton = () => {
setSelectedProducts([]);
}
return (
<React.Fragment>
<div className='container'>
<h1 className='display-3 text-center'>New Sale</h1>
<div className='row'>
<div className='col'>
<div className='mb-3'>
<label htmlFor='product' className='form-label fs-3'>Service</label>
<select id='product' onChange={handleSelectChange} className='form-select form-select-lg' multiple aria-label='multiple select service'>
{products.length !== 0?
products.map(item => <option key={item.id} value={item.id}>{item.name}</option>) : <option>No product registered</option>
}
</select>
</div>
</div>
</div>
<div className='row mt-4'>
<div className='col'>
<table className='table caption-top'>
<caption>Sell List</caption>
<thead>
<tr>
<th scope='col'>#</th>
<th scope='col'>Product</th>
<th scope='col'>Quantity</th>
</tr>
</thead>
<tbody>
{selectedProducts.length !== 0?
selectedProducts.map((item, index) => (
<tr key={index}>
<th scope='row'>{(index + 1)}</th>
<td>{item.name}</td>
<td>
<label htmlFor={`customRange-${index}`} className='form-label'>{item.quantity} Units</label>
<input
type='range'
className='form-range'
value={item.quantity}
onChange={({target}) => handleRangeChange(target, index)}
min='1'
max='100'
step='1'
id={`customRange-${index}`}/>
</td>
</tr>
)) :
<tr>
<th className='text-center' colSpan='3'>Nothing selected!</th>
</tr>
}
</tbody>
</table>
</div>
</div>
<div className='row mt-2'>
<div className='col'>
<button className='btn btn-success'>Save</button>
</div>
<div className='col'>
<button className='btn btn-warning' onClick={handleCancelButton}>Cancel</button>
</div>
</div>
</div>
</React.Fragment>
)
};
export default NewSale;
The code shows this... I do not know if I'm allowed to do this kind of operations because I'm adding events every time I select a product so, I'm not sure this is the best way to do it.
And the problem is that I'm getting this unexpected result,
What I want to do is show the current Quantity for each selected item,
Thanks!!