React JS creating percentage chart - reactjs

I'm working on creating a chart that will show set percentages of a user-inputted number. For example the user enters "200" and the chart would show "100% = 200, 95% = 190, etc.". The percentages on the chart will stay the same, it'll be just the input number and the percentage results that will change. hopefully that makes sense.
Here is the code for the chart:
import React, { useState } from 'react';
const issStyles = {
chart: {
display: 'flex',
flexDirection: 'row',
margin: '20px',
},
percentBox: {
background: '#E7E7E7',
borderRadius: '10px',
padding: '5px',
display: 'flex',
justifyContent: 'center',
width: '200px',
fontSize: '24px',
},
percentResultBox: {
background: '#E7E7E7',
borderRadius: '10px',
padding: '5px',
display: 'flex',
justifyContent: 'center',
width: '200px',
fontSize: '24px',
},
line: {
padding: '5px',
justifyContent: 'center',
fontSize: '24px',
},
}
export default function PercentChart(props) {
const [ percent ] = useState(props.percent)
const [ percentResult ] = useState(props.percentResult)
return (
<div style={issStyles.chart}>
<div style={issStyles.percentBox}>
{percent}
</div>
<div style={issStyles.line}>
----------
</div>
<div style={issStyles.percentResultBox}>
{percentResult}
</div>
</div>
)
};
Here is the code for the page it is being called in:
import React from 'react';
import HeaderButton from '../../components/HeaderButton';
import PercentChart from '../../components/PercentChart';
const issStyles = {
PRNumber: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
margin: '20px',
fontFamily: 'PT Sans Caption',
fontSize: '18px',
},
Space: {
margin: '10px',
},
PRChart: {
background: '#C4C4C4',
width: '80%',
borderRadius: '10px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
margin: '0 auto',
},
};
export default function PercentPage() {
return (
<div>
<HeaderButton exerciseName="Movement 1" />
<div style={issStyles.PRNumber}>
PR:
<input type="number" placeholder="Enter current PR" style={issStyles.Space}/>
</div>
<div style={issStyles.PRChart}>
<PercentChart percent="100%" percentResult="100"/>
<PercentChart percent="95%" percentResult="95"/>
<PercentChart percent="90%" percentResult="90"/>
<PercentChart percent="85%" percentResult="85"/>
<PercentChart percent="80%" percentResult="80"/>
<PercentChart percent="75%" percentResult="75"/>
<PercentChart percent="70%" percentResult="70"/>
<PercentChart percent="65%" percentResult="65"/>
<PercentChart percent="60%" percentResult="60"/>
<PercentChart percent="55%" percentResult="55"/>
</div>
</div>
);
};
Here is a screenshot of what the page currently looks like:
Basically, what I want to happen is the user would enter a number in the "Enter current PR" input field, and the numbers on the right of the chart would automatically update to whatever is the corresponding percentage of that number. I know right now I have the numbers hard coded and not associated with the input field at all, and that's what I need help on mainly. I'm new to coding so any additional tips/corrections would be wonderful. Thank you!

Runnable Code Snippet
const { useEffect, useState } = React;
const { Container, Table, Form } = ReactBootstrap;
function App() {
const [pr, setPr] = useState(100);
const [levels, setLevels] = useState([]);
useEffect(() => {
const arr = [];
let percentage = 100;
while (percentage > 0) {
arr.push([percentage, (pr * percentage) / 100]);
percentage -= 5;
}
setLevels(arr);
}, [pr]);
return (
<Container>
<Form>
<Form.Group controlId="formBasicEmail">
<Form.Label>PR</Form.Label>
<Form.Control
type="input"
placeholder="100"
value={pr}
onChange={(e) => setPr(e.target.value)}
/>
</Form.Group>
</Form>
<Table striped bordered hover>
<thead>
<tr>
<th>Percent</th>
<th>Result</th>
</tr>
</thead>
<tbody>
{levels.map((level) => (
<tr key={level[0]}>
<td>{level[0]}%</td>
<td>{level[1]}</td>
</tr>
))}
</tbody>
</Table>
</Container>
);
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/react-bootstrap#next/dist/react-bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css" rel="stylesheet"/>
<div id="react"></div>
Example Code Before Mangling for Snippet
import React, { useEffect, useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import Container from "react-bootstrap/Container";
import Table from "react-bootstrap/Table";
import Form from "react-bootstrap/Form";
export default function App() {
const [pr, setPr] = useState(100);
const [levels, setLevels] = useState([]);
useEffect(() => {
const arr = [];
let percentage = 100;
while (percentage > 0) {
arr.push([percentage, (pr * percentage) / 100]);
percentage -= 5;
}
setLevels(arr);
}, [pr]);
return (
<Container>
<Form>
<Form.Group controlId="formBasicEmail">
<Form.Label>PR</Form.Label>
<Form.Control
type="input"
placeholder="100"
value={pr}
onChange={(e) => setPr(e.target.value)}
/>
</Form.Group>
</Form>
<Table striped bordered hover>
<thead>
<tr>
<th>Percent</th>
<th>Result</th>
</tr>
</thead>
<tbody>
{levels.map((level) => (
<tr key={level[0]}>
<td>{level[0]}%</td>
<td>{level[1]}</td>
</tr>
))}
</tbody>
</Table>
</Container>
);
}
I used React Bootstrap for formatting. The idea is you have the form field for the user to enter a number. When it changes, the onEffect fires and parses the input. Then it calculates the percentages and places them in an array. The array is set as the "levels" and we use the map method to render the table.

Related

Setting content editable returns Cannot create property 'contentEditable' on string error

I am visualising a List of Cards with content and what I want to achieve is to set contentEditable=true to the clicked card via its button. I am able to select the content of the element, however contentEditable is not set to true and it returns the following error instead:
Uncaught TypeError: Cannot create property 'contentEditable' on string
And I cant figure out why. What am I doing wrong here and how can I set contentEditable to true for the clicked element via its button?
Here is my code:
import * as React from 'react';
import { ListView } from '#progress/kendo-react-listview';
import { Input } from '#progress/kendo-react-inputs';
import {
Card,
CardTitle,
CardImage,
CardActions,
CardBody,
} from '#progress/kendo-react-layout';
import { Pager } from '#progress/kendo-react-data-tools';
import articles from '../data/articles.json';
import { BubbleChart } from "../components/products/BubbleChart"
const onEdit = (item) => {
console.log(item.Content)
let cardContent = item.Content.contentEditable = "true";
return cardContent
}
const MyItemRender = (props) => {
let item = props.dataItem;
return (
<div
style={{
padding: '20px 20px',
}}
className="parent-container"
>
<div className="k-card-list">
<Card
style={{
width: 260,
height: 340
}}
>
<CardBody
style={{
borderBottom: 'solid 1px rgba(0,0,0,.08)'
}}
>
<CardImage
src={require(`../assets/article-images/${item.Image}`)}
style={{
width: 260,
height: 140,
maxWidth: 260,
}}
/>
<CardTitle
style={{
fontSize: 18,
}}
/>
<CardTitle>{item.Title}</CardTitle>
<CardTitle>{item.Subtitle}</CardTitle>
<p className="content">
Some quick example text to build on the card title and make up the
bulk of the card content.
</p>
</CardBody>
<CardActions>
<div className="footer-buttons-container">
<span>
<span className="k-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-base">
<span className="k-icon k-i-preview"></span>Review
</span>
</span>
<span>
<span className="k-button k-edit-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-primary" onClick={() => onEdit(item)}>
<span className="k-icon k-i-edit"></span>Edit
</span>
</span>
</div>
</CardActions>
</Card>
</div>
</div>
);
};
export const Products = () => {
const [filteredList, setFilteredList] = React.useState(articles);
const [value, setValue] = React.useState('');
const [page, setPage] = React.useState({
skip: 0,
take: 10,
});
const handlePageChange = (e) => {
setPage({
skip: e.skip,
take: e.take,
});
};
const handleChange = React.useCallback((event) => {
setValue(event.target.value);
const results = articles.filter(post => {
if (event.target.value === "") return articles
return post.Title.includes(event.target.value)
})
console.log(results)
setFilteredList(results)
});
const { skip, take } = page;
return <div>
<div className="chart-container">
<br/>
<br/>
<BubbleChart/>
</div>
<div className="input-container">
<Input
style={{
border: '2px solid #ccc',
boxShadow: 'inset 0px 0px 0.5px 0px rgba(0,0,0,0.0.1)',
}}
placeholder={'Search'}
value={value}
onChange={handleChange}
/>
</div>
<div className="listbox-card-container">
<ListView
data={filteredList.slice(skip, skip + take)}
item={MyItemRender}
style={{
width: '100%',
height: '100%',
}}
/>
<Pager
skip={skip}
take={take}
onPageChange={handlePageChange}
total={articles.length}
/>
</div>
</div>
}
Can't do multiple assigning in one line. add separate lines
const onEdit = (item) => {
console.log(item.Content)
const content = {...item.Content }
content.contentEditable = "true";
return content
}

Getting an error titled "Uncaught TypeError: Cannot read properties of undefined (reading 'cartFoodItems')" when clicking on my cart button

I am working on a food app that adds items to a cart then calculates the total amount. I am trying to implement a reducer as opposed to having multiple instances of state hooks and I am running into this error when trying to click open my cart modal.
I know the items are being added successfully to the cart because when I add them, then inspect in the console and remove the "display: none " property from my modal and see the added food items there. For some reason its specifically when I click my cart to see the modal is when I receive the error.
The error message is saying the error is located in my app.js file where I assign define the cartFoods prop to my Cartmodal component
App.js Component
import logo from "./logo.svg";
import "./App.css";
import NavHeader from "./NavHeader";
import { useState, useEffect, useReducer } from "react";
import FoodList from "./FoodList";
import CartModal from "./CartModal";
import "animate.css";
function App() {
const [foods, setFoods] = useState([
{
food: "sushi roll",
description: "fresh tuna topped with eel sauce and avocado",
price: "14.99",
quantity: 1,
},
{
food: "pizza",
description: "baked to a crisp with mozarrella, basil and tomato sauce",
price: "9.99",
quantity: 1,
},
{
food: "special fried rice",
description: "cooked with onions , shrimp , chicken",
price: "19.99",
quantity: 1,
},
{
food: "tacos",
description:
"choice of either ,shrimp , chicken, or steak, topped with pico de gallo",
price: "15.99",
quantity: 1,
},
]);
const [totalFoodAmount, setTotalFoodAmount] = useState(0);
// const [modalDisplay, setModalDisplay] = useState("none");
const [totalPrice, setTotalPrice] = useState(0);
const [cartFoods, setCartFoods] = useState([]);
const [cartItem, setCartItem] = useState({});
const [modalDisplay, setModalDisplay] = useState("none");
const [amountValue, setAmountValue] = useState(0);
function foodReducer(state, action) {
if (action.type === "ADD_CART_ITEMS") {
return { cartFoodItems: state.cartFoodItems.concat(action.val) };
}
}
const [foodState, dispatch] = useReducer(foodReducer, {
modalDisplay: "none",
totalFoodPrice: 0,
cartFoodItems: [],
});
function setDisplay() {
dispatch({ type: "ADD_MODAL_DISPLAY" });
setModalDisplay("flex");
}
function removeModal() {
dispatch({ type: "REMOVE_MODAL_DISPLAY" });
setModalDisplay("none");
}
function setQuantity(e) {
console.log(e.target.value);
setAmountValue(e.target.value);
}
function addFood(food) {
console.log(food);
let newFoodItem = { ...food, quantity: amountValue };
// setCartFoods((prevState) => cartFoods.concat(newFoodItem));
dispatch({ type: "ADD_CART_ITEMS", val: newFoodItem });
// ask slavo specific question on why state doesnt update right away when you console.log(cartFoods) inside the function
}
useEffect(() => {
let total = foodState.cartFoodItems.reduce(function (a, b) {
return a + Number(b.quantity);
}, 0);
setTotalFoodAmount(total);
foodState.cartFoodItems.map((food) =>
setTotalPrice(totalPrice + food.price * food.quantity)
);
}, [foodState]);
return (
<div className="App">
<NavHeader cartQuantity={totalFoodAmount} setDisplay={setDisplay} />
<FoodList foodList={foods} addFood={addFood} setAmount={setQuantity} />
<CartModal
cartFoods={foodState.cartFoodItems}
display={modalDisplay}
closeModal={removeModal}
totalPrice={totalPrice}
/>
</div>
);
}
export default App;
Cart.js component
import React from "react";
export default function Cart(props) {
return (
<div
style={{
display: "flex",
marginRight: "35px",
border: "1px solid lightgray",
padding: "5px",
borderRadius: "5px",
margin: "10px",
}}
className="cart-section"
onClick={props.setDisplay}
>
<div style={{ marginRight: "20px" }}>
<h4>Your Cart</h4>
</div>
<div style={{ position: "relative", top: "0vh" }}>
<h4>Quantity: {props.cartQuantity}</h4>
</div>
</div>
);
}
CartModal.js
import React from "react";
import "animate.css";
import { CSSTransition } from "react-transition-group";
export default function CartModal(props) {
return (
<div
style={{
background: "#000000a6",
width: "100vw",
height: "100vh",
position: "fixed",
top: "0",
left: "0",
overflow: "scroll",
display: props.display,
justifyContent: "center",
alignItems: "center",
}}
>
<div
style={{
background: "white",
padding: "30px",
minHeight: "60vh",
minWidth: "75vw",
borderRadius: "10px",
}}
className="cart-modal"
>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<h3 onClick={props.closeModal}>x</h3>
</div>
<h4 style={{ textAlign: "center" }}>Your Cart</h4>
{props.cartFoods.length === 0 ? (
<h1>There are no Items in your cart</h1>
) : (
props.cartFoods.map((food, index) => (
<div
style={{
display: "flex",
justifyContent: "space-between",
borderBottom: "2px solid lightgray",
}}
key={index}
>
<div style={{ width: "10vh" }}>
<h3>{food.food}</h3>
<p>{food.price}</p>
<p>Quantity: {food.quantity}</p>
</div>
<div style={{ display: "flex" }}>
<button style={{ margin: "10px", maxHeight: "20px" }}>-</button>
<button style={{ margin: "10px", maxHeight: "20px" }}>+</button>
</div>
</div>
))
)}
<h2>Price: ${props.totalPrice}</h2>
</div>
</div>
);
}

Filtering array to remove filtered object in react

Objective is to have an array with captured pokemons if user clicks on the input and an array of not-captured pokemons if user un-clicks the input. I've managed to filter out the pokemon when it's no longer captured and have it in the not-captured array but I can't seem to delete that pokemon from the old captured array.
Eg. If I click on "bulbasaur", "charmender", "squirtle", I get them all in the captured array. If I then remove one of them, I correctly get the removed one in the not-captured array but I can't seem to delete it from the previous captured array.
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import PokemonIcon from "./PokemonIcon";
const PokemonCard = ({ pokemon, capturedPkm, setCapturedPkm, notCapturedPkm, setNotCapturedPkm }) => {
const [label, setLabel] = useState('Not captured')
const toggleCaptured = (checked, id) => {
const pokemonName = { id: pokemon.id, name: pokemon.name }
if (checked && id === pokemon.id) {
setCapturedPkm([...capturedPkm, pokemonName])
setLabel('Captured!')
} else {
setLabel('Not captured!')
setNotCapturedPkm([...notCapturedPkm, pokemonName])
if (checked === false) {
let newArr = [...capturedPkm]
let pkmRemoved = newArr.filter((el, i) => el.id === id)
let newArrPkm = newArr.splice(pkmRemoved, 1)
console.log('newArr',newArrPkm, 'pkmRemoved', pkmRemoved)
setCapturedPkm(newArrPkm)
}
}
}
useEffect(() => {
console.log('captured', capturedPkm, 'not captured', notCapturedPkm)
}, [capturedPkm, notCapturedPkm])
return (
<>
<div
className="pokemon-card"
style={{
height: "250px",
maxWidth: "250px",
margin: "1rem",
boxShadow: "5px 5px 5px 4px rgba(0, 0, 0, 0.3)",
cursor: "pointer",
}}
>
<Link
to={{ pathname: `/pokemon/${pokemon.id}` }}
style={{ textDecoration: "none", color: "#000000" }}
state={{ pokemon: pokemon, capturedPkm }}
>
<div
style={{
padding: "20px",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<PokemonIcon img={pokemon.sprites?.['front_default']} />
</div>
</Link>
<div style={{ textAlign: "center" }}>
<h1>{pokemon.name}</h1>
<label>
<input type="checkbox"
defaultChecked={false}
value={pokemon.name}
onChange={(e) => toggleCaptured(e.target.checked, pokemon.id)} />
<span style={{ marginLeft: 8, cursor: 'pointer' }}>
{label}
</span>
</label>
</div>
</div>
<div></div>
</>
);
};
export default PokemonCard;
I guess you forgot to update the notCapturedPkm array. You could try something like this :
if (checked && id === pokemon.id) {
setCapturedPkm([...capturedPkm, pokemonName])
// Update this array, by removing the selected pokemon
setNotCapturedPkm([...notCapturedPkm.filter(pkm => pkm.id !== pokemon.id)])
setLabel('Captured!')
}

Materail UI TypeError: event.target.getAttribute is not a function

I am making a form in React using Material UI and displaying the form data in a table on client side, the problem is when I Select language by the select dropdown then I get an error of TypeError: event.target.getAttribute is not a function.
Although This language data is not displayed in the table but I need it, it needs to be stored in the database(which currently I have not implemented)
I have referred Material UI select throws event.target.getAttribute is not a function and also this github issue but it did not worked for me.
Currently I am not using any state management tool like redux, I am passing down props from my App component.
Please help me as in where am I going wrong
App.js
import Projects from './components/Projects';
import FormModal from './components/FormModal'
import Sidebar from './components/Sidebar';
import { useState } from 'react';
import {nanoid} from 'nanoid'
import DeleteModal from './components/DeleteModal';
function App() {
const [formDatas,setFormDatas] = useState(
[
{
projectName: 'Test',
projectId: nanoid(),
nameSpace: 'John Doe'
},
])
// Show Table State
const [showTable, setShowTable] = useState(false)
// HOOKS FORM MODAL
const [addFormData, setAddFormData] = useState({
projectName: '',
projectDescription: '',
nameSpace: '',
language: ''
})
const handleAddFormChange = (event) => {
event.preventDefault()
const fieldName = event.target.getAttribute('name')
console.log(fieldName)
const fieldValue = event.target.value
const newFormData = {...addFormData}
newFormData[fieldName] = fieldValue
setAddFormData(newFormData)
}
// FORM SUBMIT HANDLER
const handleAddFormSubmit = (event) => {
event.preventDefault()
const newProject = {
projectId: nanoid(),
projectName: addFormData.projectName,
projectDescription: addFormData.projectDescription,
nameSpace: addFormData.nameSpace,
language: addFormData.language
}
// Copy all the previous formDatas and add newProject Data
const newProjects = [...formDatas, newProject ]
setFormDatas(newProjects)
// console.log(newProject)
// Clear Form Input Fields after Submitting
setAddFormData({
projectName: '',
projectDescription: '',
nameSpace: '',
language: ''
})
// After Submitting close Form Modal
handleClose()
}
// Delete Handler
const deleteModalHandler = (addFormData) => {
console.log(addFormData.projectId)
}
// MODAL OPEN CLOSE STATE
const [open, setOpen] = useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
return (
<>
<Sidebar showTable = {showTable} setShowTable = {setShowTable}/>
<FormModal addFormData = {addFormData}
handleAddFormChange = {handleAddFormChange}
handleAddFormSubmit = {handleAddFormSubmit}
open = {open}
handleOpen = {handleOpen}
handleClose = {handleClose}/>
<Projects
formDatas = {formDatas}
addFormData = {addFormData}
deleteModalHandler={deleteModalHandler}
showTable = {showTable}
setShowTable = {setShowTable}/>
</>
);
}
export default App;
FormModal.js
import * as React from 'react';
import Box from '#mui/material/Box';
import Button from '#mui/material/Button';
import { TextField } from "#mui/material";
import Modal from '#mui/material/Modal';
import InputLabel from '#mui/material/InputLabel';
import MenuItem from '#mui/material/MenuItem';
import Select from '#mui/material/Select';
import { useState } from 'react';
import SearchIcon from '#mui/icons-material/Search';
import { InputAdornment } from '#mui/material';
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
export default function FormModal({handleAddFormChange, addFormData,handleAddFormSubmit,open,handleOpen,handleClose}) {
return (
<div>
<Box sx = {{display: 'flex', justifyContent: 'flex-end',alignItems: 'flex-end', flexDirection: 'column'}}>
<Button sx = {{ marginTop: '5%', marginRight: '4%', borderRadius: '10px '}} variant="contained" onClick={handleOpen}>Create project + </Button>
{/* <input style = {{marginTop: '2.5%', marginRight: '5%', padding: '5px'}} type="text" placeholder = "Search..." /> */}
<TextField sx = {{marginTop: '2%', marginRight: '4%', padding: '5px'}} placeholder = "Search..." InputProps={{
endAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
)
}}/>
</Box>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<div style = {{height: '5vh', display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<h3>Create New Project</h3>
</div>
<form onSubmit = {handleAddFormSubmit}>
<TextField
id="outlined-basic"
label="Project Name"
name = "projectName"
variant="outlined"
fullWidth= {true}
required = {true}
margin ="normal"
value={addFormData.projectName}
onChange={handleAddFormChange}
/>
<TextField
id="outlined-basic"
label="Project Description"
name = "projectDescription"
variant="outlined"
fullWidth = {true}
required = {true}
multiline
rows = {5}
margin ="normal"
value={addFormData.projectDescription}
onChange={handleAddFormChange}
/>
<TextField
id="outlined-basic"
label="Name Space"
name = "nameSpace"
variant="outlined"
fullWidth= {true}
required = {true}
autoComplete = {Math.random().toString()}
margin = "normal"
value={addFormData.nameSpace}
onChange={handleAddFormChange}
/>
<InputLabel id="demo-simple-select-label">Select Language</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
name = "name"
value={addFormData.language}
onChange={handleAddFormChange}
style = {{width: '100%'}}
>
<MenuItem value="english">English</MenuItem>
</Select>
<br />
<div style = {{display: 'flex', alignItems: 'center', justifyContent: 'space-evenly', marginTop: '7%'}}>
<Button style = {{width: '40%'}} variant = "contained" type="submit">Submit</Button>
<Button style = {{width: '40%'}} variant = "contained" onClick = {handleClose}>Cancel</Button>
</div>
</form>
</Box>
</Modal>
</div>
);
}
Projects.js
import React from "react";
import EditModal from "./EditModal";
import DeleteModal from "./DeleteModal";
import { styled } from "#mui/material/styles";
import Table from "#mui/material/Table";
import TableBody from "#mui/material/TableBody";
import TableCell, { tableCellClasses } from "#mui/material/TableCell";
import TableContainer from "#mui/material/TableContainer";
import TableHead from "#mui/material/TableHead";
import TableRow from "#mui/material/TableRow";
import { useState } from "react";
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
// backgroundColor: theme.palette.common.black,
backgroundColor: "#1976D2",
color: theme.palette.common.white,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
},
}));
const StyledTableRow = styled(TableRow)(({ theme }) => ({
"&:nth-of-type(odd)": {
backgroundColor: theme.palette.action.hover,
},
// hide last border
"&:last-child td, &:last-child th": {
border: 0,
},
}));
const Projects = ({ showTable, setShowTable,addFormData, formDatas,deleteModalHandler}) => {
//const [showTable, setShowTable] = useState(true
return (
<div style={{ display: "flex", alignItems: "center", marginTop: "7%" }}>
{showTable ? <TableContainer > {/*component={Paper}*/}
<Table sx={{ width: '50%', marginLeft: 'auto', marginRight: 'auto' }} aria-label="customized table">
<TableHead>
<TableRow>
<StyledTableCell align="left">Project Name</StyledTableCell>
<StyledTableCell align="left">Project Id</StyledTableCell>
<StyledTableCell align="left">Created By</StyledTableCell>
<StyledTableCell align="center">Operations</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{formDatas.map((formData) => (
<StyledTableRow key = {formData.projectId}>
<StyledTableCell align="left" component="th" scope="row">
{formData.projectName}
</StyledTableCell>
<StyledTableCell align="left">
{formData.projectId}
</StyledTableCell>
<StyledTableCell align="left">
{formData.nameSpace}
</StyledTableCell>
<StyledTableCell align="center">
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-evenly",
}}
>
<EditModal />
<DeleteModal deleteModalHandler = {deleteModalHandler}/>
</div>
</StyledTableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>: null}
</div>
);
};
export default Projects;
As mentioned #Pradip Dhakal in the comment <Select> only return the {name: '', value: ''} as a target object, this is causing the issue. There is no other objects.
So I used Material UI Native Select Component and it solved the problem
The only code that I changed in FormModal.js file is below.
<NativeSelect
// defaultValue={30}
value={addFormData.language}
onChange={handleAddFormChange}
inputProps={{
name: 'language',
id: 'uncontrolled-native',
}}
>
<option value = "" disabled>Select</option>
<option value={'english'}>English</option>
<option value={'german'}>German</option>
</NativeSelect>
This is the minimal code that I've try, and it's working fine in my end.
material UI version: "#material-ui/core": "^4.11.0",
// FormModal.js
import React from 'react';
import { TextField } from "#material-ui/core"
export const FormModal = ({ handleAddFormChange }) => {
return (
<TextField
id="outlined-basic"
label="Project Name"
name="projectName"
variant="outlined"
fullWidth={true}
required={true}
margin="normal"
value=""
onChange={handleAddFormChange}
/>
);
}
// app.js
import React from 'react';
import { TextField } from "#material-ui/core"
import { FormModal } from "./FormModal"
const App = () => {
const handleAddFormChange = (event) => {
event.preventDefault()
const fieldName = event.target.getAttribute('name')
console.log("Name: ", fieldName)
}
return (
<FormModal handleAddFormChange={handleAddFormChange} />
);
}
Can you please try to breakdown your code, and start from the basic one.

How to submit the form so that it is displayed in the table?

I created a form at the top that allows the user to enter in a first name, last name, and phone number and submit button.
Once the submit button is pressed, the information should be displayed in a table below (automatically sorted by last name) along with all the previous information that was entered.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const style = {
table: {
borderCollapse: 'collapse'
},
tableCell: {
border: '1px solid gray',
margin: 0,
padding: '5px 10px',
width: 'max-content',
minWidth: '150px'
},
form: {
container: {
padding: '20px',
border: '1px solid #F0F8FF',
borderRadius: '15px',
width: 'max-content',
marginBottom: '40px'
},
inputs: {
marginBottom: '5px'
},
submitBtn: {
marginTop: '10px',
padding: '10px 15px',
border:'none',
backgroundColor: 'lightseagreen',
fontSize: '14px',
borderRadius: '5px'
}
}
}
function PhoneBookForm({ addEntryToPhoneBook }) {
return (
<form onSubmit={ e => { e.preventDefault() }} style={style.form.container}>
<label>First name:</label>
<br />
<input
style={style.form.inputs}
className='userFirstname'
name='userFirstname'
type='text'
value='Coder'
/>
<br/>
<label>Last name:</label>
<br />
<input
style={style.form.inputs}
className='userLastname'
name='userLastname'
type='text'
value='Byte'
/>
<br />
<label>Phone:</label>
<br />
<input
style={style.form.inputs}
className='userPhone'
name='userPhone'
type='text'
value='8885559999'
/>
<br/>
<input
style={style.form.submitBtn}
className='submitButton'
type='submit'
value='Add User'
/>
</form>
)
}
function InformationTable(props) {
return (
<table style={style.table} className='informationTable'>
<thead>
<tr>
<th style={style.tableCell}>First name</th>
<th style={style.tableCell}>Last name</th>
<th style={style.tableCell}>Phone</th>
</tr>
</thead>
</table>
);
}
function Application(props) {
return (
<section>
<PhoneBookForm />
<InformationTable />
</section>
);
}
ReactDOM.render(
<Application />,
document.getElementById('root')
);
// .....
// .....
// You should have a state where you can store the value of the form to pass it
// to the other component
// I just summarize the code.
function PhoneBookForm(props) {
const [firstname, setFirstname] = useState('');
// const [lastname, setLastname] = useState('');
submitForm(){
// you can do other things about the values of state
props.saveFn({ firstname : firstname });
}
return (
<form onSubmit={ e => { e.preventDefault() }} style={style.form.container}>
<label>First name:</label>
<br />
<input
style={style.form.inputs}
className='userFirstname'
name='userFirstname'
type='text'
onChange={e => setFirstname(e.target.value)}
value={firstname}
/>
<br/>
<input
style={style.form.submitBtn}
className='submitButton'
type='submit'
value='Add User'
onClick={ submitForm }
/>
</form>
)
}
function InformationTable(props) {
return (
<table style={style.table} className='informationTable'>
<thead>
<tr>
<th style={style.tableCell}>First name</th>
</tr>
{
props.Items.map((item,idx) => <tr style={style.tableCell} key={idx}> <td>{item.firstname} </td></tr>)
}
</thead>
</table>
);
}
function Application(props) {
const [items, setItems] = useState([]);
function addItem(newItem){
let sorted_item = [];
// add newItem here and
// sort your items here
setItems(sorted_item)
}
return (
<section>
<PhoneBookForm saveFn={addItem}/>
<InformationTable Items={items}/>
</section>
);
}
ReactDOM.render(
<Application />,
document.getElementById('root')
);
There are several ways to do this. I only fix the Name for you and let you figure out the rest. So basically you have to create a state (useState) in your parent component (Application) and pass it down to via props to the two children components (PhoneBookForm and InformationTable). In the PhoneBookForm, you call the addEntryToPhoneBook function to update the state (i.e. adding names to the phonebook. In the InformationTable, you only have to render the state addEntryToPhoneBook from parent compnent.
https://i.imgur.com/lzWzKj0.png
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const style = {
table: {
borderCollapse: 'collapse'
},
tableCell: {
border: '1px solid gray',
margin: 0,
padding: '5px 10px',
width: 'max-content',
minWidth: '150px'
},
form: {
container: {
padding: '20px',
border: '1px solid #F0F8FF',
borderRadius: '15px',
width: 'max-content',
marginBottom: '40px'
},
inputs: {
marginBottom: '5px'
},
submitBtn: {
marginTop: '10px',
padding: '10px 15px',
border: 'none',
backgroundColor: 'lightseagreen',
fontSize: '14px',
borderRadius: '5px'
}
}
}
function PhoneBookForm(props) {
//Create a function to handle when info is submit.
const handleFirstName = (e) => {
e.preventDefault();
//Updating the state of the parent using spread operator.
//This is a standard way to update state since it's immutatble.
//i.e. you update it via making a copy and adding new info
props.addEntryToPhoneBook([...props.phoneBook, document.getElementById('firstName').value]);
}
return (
<form style={style.form.container}>
<label>First name:</label>
<br />
{/*Note: replace value with placeholder because value need to be able to change.*/}
<input
id='firstName'
style={style.form.inputs}
className='userFirstname'
name='userFirstname'
type='text'
placeholder='Coder'
/>
<br />
<label>Last name:</label>
<br />
<input
style={style.form.inputs}
className='userLastname'
name='userLastname'
type='text'
placeholder='Byte'
/>
<br />
<label>Phone:</label>
<br />
<input
style={style.form.inputs}
className='userPhone'
name='userPhone'
type='text'
placeholder='8885559999'
/>
<br />
<input
onClick={handleFirstName}
style={style.form.submitBtn}
className='submitButton'
type='submit'
placeholder='Add User'
/>
</form>
)
}
function InformationTable({ phoneBook }) {
return (
<table style={style.table} className='informationTable'>
<thead>
<tr>
<th style={style.tableCell}>First name</th>
<th style={style.tableCell}>Last name</th>
<th style={style.tableCell}>Phone</th>
</tr>
</thead>
{/*Rendering the info in phoneBook via mapping*/}
{
phoneBook.map(data =>
<tr key={data}>
<th>
{data}<br />
</th>
</tr>
)}
</table>
);
}
function Application() {
//Create a state here to store all your data in the phonebook.
const [phoneBook, addEntryToPhoneBook] = useState([]);
console.log('userInfo parent: ', phoneBook)
//Since you have to pass down two props, you can use objects like this.
let props = {
phoneBook: phoneBook,
addEntryToPhoneBook: addEntryToPhoneBook
}
return (
<section>
{/*Passing down two props using spread operator*/}
<PhoneBookForm {...props} />
{/*Only passing down one prop here because you're don't need to display the data.*/}
<InformationTable phoneBook={phoneBook} />
</section>
);
}
export default Application;

Resources