I am making a cooking app that adds up the total amount of ingredients for each recipe the user adds.
For example, the user adds "Cheese Burger" as the title and in that component it would have an input box to type in name of the ingredient then another input field for the amount of ingredients. At the end of the program I want to allow the user to click a button called "Add/Build Grocery list" at the end, but unsure how to match the different ingredients to the number value of that ingredient.
You mean something like this might help?
import React, { Component } from "react";
import "./styles.css";
class App extends Component {
state = {
Items: {},
CurItem: "",
Quantity: 0
};
render() {
return (
<div className="App">
<form
onSubmit={(e) => {
e.preventDefault();
const Items = { ...this.state.Items };
if (typeof Items[this.state.CurItem] === "undefined") {
Items[this.state.CurItem] = +this.state.Quantity;
} else {
Items[this.state.CurItem] += +this.state.Quantity;
}
this.setState({
Items,
CurItem: "",
Quantity: 0
});
}}
>
<label>
<strong>Item Name:</strong>
<input
type="text"
value={this.state.CurItem}
onChange={(e) => this.setState({ CurItem: e.target.value })}
/>
</label>
<label>
<strong>Quantity:</strong>
<input
type="number"
value={this.state.Quantity}
onChange={(e) => this.setState({ Quantity: e.target.value })}
/>
</label>
<input type="submit" />
</form>
<table border="1" width="50%">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{Object.keys(this.state.Items).map((item) => (
<tr>
<td>{item}</td>
<td>{this.state.Items[item]}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default App;
See demo here: https://j6fv7.csb.app/
Preview
Related
I have a table that can add and delete rows. However, am not able to validate the table. if the table cells are empty or filled am not able to post the values to the backend. The error message still shows.What is the best way to validate the table. I would like to have the error message show if the fields are empty on submit.
payment.js
import React, {Component } from "react";
import "bootstrap/dist/css/bootstrap.min.css"
import axios from "axios"
import SimpleReactValidator from "simple-react-validator"
import Box from '#mui/material/Box';
import Button from "#mui/material/Button";
import BillTable from "./billTable"
import $ from 'jquery'
class Payment extends Component {
constructor(){
super()
this.state = {
Bill:"",
billTable: [{
index: Math.random(),
serialNumber: "",
item:"",
cost:""}],
errorMessage: '',
}
this.validator = new SimpleReactValidator({autoForceUpdate: this,messages: {
default: 'Please enter this field!'
},element: message => <div style={{color: "red"}}>{message}</div>})
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange = (e) => {
if (["serialNumber", "item", "cost"].includes(e.target.name)) {
let billTable = [...this.state.billTable]
billTable[e.target.dataset.id][e.target.name] = e.target.value;
}
else {
this.setState({ [e.target.name]: e.target.value })
}
};
addNewRowPlan = () => {
this.setState((prevState) => ({
billTable: [...prevState.billTable, { index: Math.random(), serialNumber: "", item: "", cost:""}],
}));
}
deleteRow = (index) => {
this.setState({
billTable: this.state.billTable.filter((s, sindex) => index !== sindex),
});
}
clickOnDelete(record) {
this.setState({
billTable: this.state.billTable.filter(r => r !== record),
});
}
handleSubmit(event){
event.preventDefault()
if(this.validator.allValid()){
this.validator.hideMessages()
const billed = {
Bill:this.state.billTable
};
axios.post(`http://localhost:4000/bill`, billed,{
})
.then(response => {
console.log(response.data)
return $('.alert-success').show();
})
this.setState({
Bill:"",
})
}
else{
this.validator.showMessages()
this.forceUpdate()
return $('.alert-danger').show();
}
}
render() {
let {billTable} = this.state
return (
<div>
<div className="container">
<div className="form-div">
<h1>Billing</h1>
<Box component="form" onSubmit={this.handleSubmit} noValidate sx={{ mt: 1}} onChange={this.handleChange}>
<div className="row" style={{ marginTop: 20 }}>
<div className="col-sm-3"></div>
<div className="col-sm-12">
<div className="card">
<div className="card-header text-center">Bill</div>
<div className="card-body">
<div className="row">
<div className="col-sm-4">
</div>
</div>
<table>
<thead>
<tr>
<th>Serial #</th>
<th>Item</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
<BillTable id="bill" add={this.addNewRowPlan.bind(this)} delete={this.clickOnDelete.bind(this)} billTable={billTable} />
{this.validator.message('bill',this.state.Bill,'required')}
</tbody>
</table>
</div>
</div>
</div>
<div className="col-sm-1"></div>
</div>
<Button
type="submit"
fullWidth
sx={{ mt: 3, mb: 2}}
>
<span>Submit</span>
</Button>
</Box>
</div>
</div>
</div>
);
}
}
export default Payment;
billTable.js
import React from "react"
const billTable = (props) => {
return (props.billTable.map((val, idx) => {
let serialNumber = `serialNumber-$${idx}`, item = `item-$${idx}`, cost = `cost-$${idx}`
return (
<tr key={val.index}>
<td>
<input type="text" name="serialNumber" data-id={idx} id={serialNumber} className="form-control" />
</td>
<td>
<input type="text" name="item" data-id={idx} id={item} className="form-control " />
</td>
<td>
<input type="text" name="cost" data-id={idx} id={cost} className="form-control"/>
</td>
<td>
{
idx===0?<button onClick={()=>props.add(idx)} type="button" className="btn btn-primary">Add Row</button>
: <button className="btn btn-danger" onClick={(() => props.delete(val))} >Delete Row</button>
}
</td>
</tr>
)
})
)
}
export default billTable
`````````````````````
How can i correct this code. Thank you in advance
So I am building an appointment app where if someone is sick i need to change the color of that person to red.
I am working with useState for this. My problem is that when i want to change that person my event handler doesnt target the person i want to. Can someone help me with that please?
this is my code
import React, {useState} from "react";
import {clients} from "./utils"
import "./userlist.css"
const AddClient = ({addContact}) => {
const [client, setClient] = useState(clients)
const onChangeClient = (e) =>{
setClient({...client, [e.target.name] : e.target.value})
}
const handleSubmit = (e) =>{
e.preventDefault();
addContact(client);
setClient({first_name: client.first_name,
last_name: client.last_name,
phone: client.phone,
email: client.email
});}
const isSick = client.isSick
const handleSick = () =>{
setClient(client => ({ ...client, [isSick]: !client[isSick]})
)
console.log('working')
setClient(prevState => {
console.log("prevState",prevState)
return prevState
})
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value = {client.first_name}
placeholder="name"
name = "first_name"
onChange={onChangeClient}/>
<input
type="text"
value = {client.last_name}
name="last_name"
placeholder="surname"
onChange={onChangeClient}/>
<input
type="email"
value = {client.email}
name="email"
placeholder="email"
onChange={onChangeClient}/>
<input
type="number"
value = {client.number}
name="phone"
placeholder="phone"
onChange={onChangeClient}/>
<button >Add Client</button>
</form>
<tbody className="tablerow">
{clients.map((client) => (
<tr className="table-row" style={{backgroundColor: isSick && 'red'}} key={client.phone}>
<td className=" col col-1">{client.first_name}</td>
<td className=" col col-2">{client.last_name}</td>
<td className=" col col-3">{client.email}</td>
<td className=" col col-4">{client.phone}</td>
<td><button key={client.phone} onClick={() => handleSick()}>Sick</button></td>
</tr> )
)}
</tbody>
</div>
)}
export default AddClient
this is what i see on the console
Check this working implementation of what you are trying to do: https://stackblitz.com/edit/react-avueyp?file=src%2FApp.js
Consider that we are using a static array of objects as our data model ( clients ), usually you would use data retrieved by a database, so every update to any of that data will have to be written on the db and updated data has to be sent back to th client. React UI will only care to render that updated data.
I have these 2 functions for my form in react, the first one uses react-hook-form and gets me the data from the inputs fields seen below.
The second one makes an order to buy, i just need to get the data from the first one in the "order.buyer = {}"
Imports
import { useCartContext } from './../../context/CartContext';
import { Button } from 'react-bootstrap'
import { v4 as uuidv4 } from 'uuid';
import { useForm } from 'react-hook-form';
Functions
function Cart() {
const { cartList, emptyCart, deleteItem, sumaTotal } = useCartContext();
const { register, handleSubmit } = useForm();
const onSubmit = (data) => {
console.log(data)
}
function generarOrden(data) {
let orden = {}
orden.buyer = (data);
orden.total = sumaTotal();
orden.date = new Date();
orden.items = cartList.map(cartItem => {
const id = cartItem.id
const nombre = cartItem.name
const precio = cartItem.price * cartItem.cantidad
return {id, nombre, precio}
})
console.log(orden);
}
Cart section + Form with inputs
return (
<>
<div className='tables'>
<table>
<thead>
<tr>
<th>Imagen</th>
<th>Nombre</th>
<th>Categoria</th>
<th>Descripcion</th>
<th>Cantidad</th>
<th>Precio</th>
<th>Total</th>
<th>Eliminar</th>
</tr>
</thead>
<tbody>
{cartList.map(prod =>
<tr key={uuidv4()}>
<td><img src={prod.imgSource} alt="foto" className='img-cart'/> </td>
<td>{prod.name} </td>
<td>Games</td>
<td>{prod.desc} </td>
<td>{prod.cantidad} </td>
<td>${prod.price} </td>
<td>${prod.price * prod.cantidad} </td>
<td><Button className='button-card' onClick={()=>deleteItem(prod.id)}>Quitar Item</Button></td>
</tr>
)}
</tbody>
</table>
</div>
<div>
<h4 className='cart-orden space'> Total de la compra: ${sumaTotal()} </h4>
<Button onClick={emptyCart} className="button-card space">Empty Cart</Button>
<Button onClick={generarOrden} className="button-card space">Generar Orden</Button>
<form className='container-fluid bg-dark' onSubmit={handleSubmit(onSubmit)}>
<div className="mb-3">
<label className="form-label">Name</label>
<input type="text" className="form-control" placeholder='Alejandro Otero' name='name' {...register('name', { required: true })}/>
</div>
<div className="mb-3">
<label className="form-label">Email</label>
<input type="email" className="form-control" placeholder='Example#gmail.com' name='email' {...register('email', { required: true })}/>
</div>
<div className="mb-3">
<label className="form-label">Phone Number</label>
<input type="number" className="form-control" placeholder='11-4058-8867' name='phone' {...register('phone', { required: true })}/>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
</>
)
}
export default Cart
Is a simply "problem" but im a complete noob with react/js so i cant find the way to give the data from onSubmit to generarOrden
Use react-hook-form getValues
Example:
const { register, handleSubmit, getValues } = useForm();
<button
type="button"
onClick={() => {
const values = getValues(); // { test: "test-input", test1: "test1-input" }
const singleValue = getValues("test"); // "test-input"
const multipleValues = getValues(["test", "test1"]);
// ["test-input", "test1-input"]
}}
>
You could use the watch function react hook provides. Docs
And how you can use it for your use case is:
function getOrder(){
let order = {
buyer: watch("data"), # replace data with the name you need
some: "other fields might go here",
}
# ....rest
}
i am building a table with SQLite Data in React. But i have troubles with passing the [parts] from a specific table row to another function which should show a detail view of the table Row.
This is the table itself:
class Table extends Component {
constructor(props) {
super(props)
this.state = {
parts: [],
isLoading: false,
isError: false,
show: false
}
}
async componentDidMount() {
this.setState({ isLoading: true })
const response = await fetch(`${API_ENDPOINT}/api/bestand`)
if (response.ok) {
const parts = await response.json()
this.setState({ parts, isLoading: false })
} else {
this.setState({ isError: true, isLoading: false })
}
}
render() {
const { parts, isLoading, isError, show } = this.state
if (isLoading) {
return <div>Loading...</div>
}
if (isError) {
return <div>Error</div>
}
if (show === true) {
return this.state.show && this.editSection()
}
return parts.length > 0
? (
<table className="table" id="tblData" >
<thead>
<tr>
<th style={{borderTopLeftRadius: "4px"}}>Teilenummer</th>
<th>Hersteller</th>
<th>Beschreibung</th>
<th>Preis</th>
<th style={{borderTopRightRadius: "4px"}}>SKU</th>
</tr>
</thead>
<tbody>
{this.renderTableRows()}
</tbody>
</table>
) : (
<div>
No parts.
</div>
)
}
renderTableHeader = () => {
return Object.keys(this.state.parts[0]).map(attr =>
<th key={attr} >
{attr}
</th>)
}
renderTableRows = () => {
return this.state.parts.map(part => {
return (
<tr key={part.id} onClick={this.toggle}>
<td>{part.Teilenummer}</td>
<td>{part.Hersteller}</td>
<td>{part.Beschreibung}</td>
<td>{part.Preis}</td>
<td>{part.SKU}</td>
</tr>
)
})
}
with a toggle function i open a view with a form, and all the data from the row i clicked inside as a value.
toggle = () => {
this.setState((currentState) => ({ show: !currentState.show }))
}
detailview:
editSection = () => {
return this.state.parts.map(part => {
return (
<div>
<button className="detailClose" onClick={this.toggle}>✕</button>
<form key={part.id} method="POST">
<div className="Teilenummer">
<label>
Teilenummer:
<br />
<input
type="JSON"
className="teilenrinput"
name="Teilenummer"
id="Teilenummer"
value={part.Teilenummer}
required
/>
<br />
<br />
</label>
</div>
<div className="SKU">
<label>
SKU:
<br />
<input
type="text"
name="SKU"
className="skuinput"
id="SKU"
value={part.SKU}
required
/>
<br />
<br />
</label>
</div>
<div className="Price">
<label>
Preis:
<br />
<input
type="text"
name="Price"
className="priceinput"
id="Preis"
value={part.Preis}
required
/>
<br />
<br />
</label>
</div>
<div className="Hersteller">
<label>
Hersteller:
<br />
<input
list="manufacturers"
name="Hersteller"
id="Hersteller"
className="herstellerinput"
value={part.Hersteller}
required
></input>
<datalist id="manufacturers">
<option value="Volkswagen">Volkswagen</option>
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Mercedes">Mercedes</option>
<option value="Opel">Opel</option>
</datalist>
</label>
</div>
<div className="Beschreibung">
<label>
Beschreibung:
<br />
<input
type="text"
name="Beschreibung"
className="beschreibunginput"
id="Beschreibung"
value={part.Beschreibung}
required
/>
<br />
<br />
</label>
</div>
<input
className="Eintragen-Button"
type="submit"
value="Update "
/>
<span id="response"></span>
<button className="deleteButton" onClick={() => this.deleteTableRow(part.id)}>Delete</button>
</form>
</div>
)
})
}
}
the problem with the current solution is, i map all the data in the editSection function and as a result i render every table row in it, when i click on one row.
how do i map the id´s in a way, that the editSection only renders the row i clicked on in the table?
regards
You need to pass part of parts.map function to the toggle function like
onClick ={part=> this.toggle(part)}.
So than on click event handler you get the row specific value.
Now you can save this part object in state along with show property in toggle function, like
setState({show: someValue, activeRow: part})
Now while loading the form popup or like so, in editSection function use the state.activeRow properly.
Seen a few questions but still not sure what to do. New to react as well. I want to update a table with the values of Title and Amount using input fields. I am pretty sure I have to set the state to a blank table and then update the state when it is updated. How do I update the table with a new row each time the 2 new values are added?
import React, { Component } from 'react';
import './App.css';
const table =
<table id="itemTable">
<tbody>
<tr><th>Title</th>
<th>Amount</th>
<th>Remove Item</th>
</tr>
</tbody>
</table>;
class App extends Component {
constructor(props){
super(props);
this.state = {
title: '',
amount: '',
table: {table}
};
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
//adds to table
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
render() {
return (
<section className="App">
<header>
<h1>Money Manager</h1>
</header>
<section>
<h1>Finances</h1>
<form>
<label htmlFor="name">Name</label>
<input type="text" name="title" onChange={this.handleChange}/>
<label htmlFor="amount">Amount</label>
<input type="text" name="amount" onChange={this.handleChange}/>
<button type="button" id="add" onClick={this.handleClick}>Add item</button>
</form>
<section>
<h1>Items</h1>
{table}
</section>
</section>
</section>
);
}
}
export default App
You should make the front of the table, and make a state for the content of the table, like this:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props){
super(props);
this.state = {
tableContent: []
};
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// Don't forget to check if the inputs are corrects
// Here i generate a random number for the key propriety that react need
let randomID = Math.floor(Math.random() * 999999);
// recreate a new object and stock the new line in
let newTab = this.state.tableContent;
newTab.push({
key: randomID,
title: "",
amount: "" // Don't forget to get the value of the inputs here
});
this.setState({
tableContent: newTab
});
// Clear the content of the inputs
// the state has changed, so the tab is updated.
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
render() {
return (
<section className="App">
<header>
<h1>Money Manager</h1>
</header>
<section>
<h1>Finances</h1>
<form>
<label htmlFor="name">Name</label>
<input type="text" name="title" onChange={this.handleChange}/>
<label htmlFor="amount">Amount</label>
<input type="text" name="amount" onChange={this.handleChange}/>
<button type="button" id="add" onClick={this.handleClick}>Add item</button>
</form>
<section>
<h1>Items</h1>
<table id="itemTable">
<thead>
<tr>
<th>Title</th>
<th>Amount</th>
<th>Remove Item</th>
</tr>
</thead>
<tbody>
{this.state.tableContent.map((item) =>
<tr key={item.key}>
<td>{item.title}</td>
<td>{item.amount}</td>
<td>
{/* Here add the onClick for the action "remove it" on the span */}
<span>Remove it</span>
</td>
<td></td>
</tr>
)}
</tbody>
</table>
</section>
</section>
</section>
);
}
}
export default App
It's not finished but i've commented what you should do and what i've done.