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
}
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
I'm trying to have an edit page to update the details of the existing object. I have some input elements to contain the value. But when I rendered the page, the values displayed in the input boxes will not allow me to change in view - when I delete or type in new, the values in the boxes will never change. Can anyone help to figure out the matter?
import React, {useEffect, useState} from "react";
import Sidebar from "../components/Sidebar";
import {FontAwesomeIcon} from "#fortawesome/react-fontawesome";
import {useNavigate, useParams} from "react-router-dom";
import Axios from "axios";
import axios from "axios";
function CourseEdit() {
let navigate = useNavigate();
const [fname, setFname] = useState("");
const [lname, setLname] = useState("");
const [gender, setGender] = useState("");
const [age, setAge] = useState("");
const [description, setDescription] = useState("");
const [payment, setPayment] = useState("0");
const [student, setStudent] = useState({});
const {id} = useParams();
const editStudent = (id) => {
Axios.put('http://localhost:3001/student_edit', {
fname: fname,
lname: lname,
gender: gender,
age: age,
description: description,
payment: payment,
id: id,
}).then(() => {
alert('Student updated');
navigate(`../students/detail/${id}`);
console.log("student updated");
});
}
useEffect(() => {
axios.get(`http://localhost:3001/students/${id}`).then((response) => {
setStudent(response.data[0]);
// console.log(response.data[0].id);
})},[id]);
return (
<div className="grid-container">
<Sidebar/>
<div className="main_content grid-2">
<div className="details">
<div className="icon" style={{color: "#f7931e"}}>
<FontAwesomeIcon icon="user"/> Edit STUDENT
<div className="back-button" onClick={() => navigate(-1)}>
<FontAwesomeIcon icon="arrow-alt-circle-left"/>BACK
</div>
</div>
<div className="detail-content" style={{marginTop: "1.2em"}}>
<table>
<tbody>
<tr>
<td className="td-left" style={{width: "100%"}}>
<label htmlFor="StudentName">Student First Name:</label>
</td>
<td className="td-right" style={{width: "85%"}}>
<input className="mb" type="text" name="studentFname" id="detail_input"
value={student.fname} onChange={(event) => {
setFname(event.target.value)
}} required/>
</td>
</tr>
<tr>
<td className="td-left" style={{width: "100%"}}>
<label htmlFor="StudentName">Student Last Name:</label>
</td>
<td className="td-right" style={{width: "85%"}}>
<input className="mb" type="text" name="studentLname" id="detail_input"
onChange={(event) => {
setLname(event.target.value)
}} value={student.lname} required/>
</td>
</tr>
...
...
...
</tbody>
</table>
<div>
<button className="green_bt option_list round mr" onClick={() => {editStudent(`${id}`)}}>Save
</button>
<button className="red_bt option_list round mr" onClick={() => navigate(-1)}>Cancel
</button>
</div>
</div>
</div>
</div>
</div>
)
}
export default CourseEdit;
To set a default value for an input element in React:
1 - Pass the default value as a parameter to the useState hook for controlled fields.
2 - Set the defaultValue prop on uncontrolled input fields
in your case you're using controlled input so you have to pass the default to useState like this :
const [fname, setFname] = useState(student.fname);
const [lname, setLname] = useState(student.lname);
and change the input field like this :
<input className="mb" type="text" name="studentFname" id="detail_input"
value={fname} onChange={(event) => { setFname(event.target.value)}}
required/>
and :
<input className="mb" type="text" name="studentLname" id="detail_input"
onChange={(event) => {setLname(event.target.value)}} value={lname}
required/>
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 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
I already upload and get the list of product successful but Update product show for me an error. I do not know how to update my image and data on Firebase in Reactjs.
This is my code in ProductForm.js
import React, { useState, useEffect } from 'react';
import Gongcha from '../asses/gongcha.jpg'
const ProductForm = (props) => {
const initialFieldValues = {
image: '',
name: '',
category: '',
price: ''
};
var [values, setValues] = useState(initialFieldValues);
var [imageFile, setImageAsFile] = useState();
useEffect(() => {
if (props.currentId == '') setValues({ ...initialFieldValues });
else
setValues({
...props.productObjects[props.currentId],
});
}, [props.currentId, props.productObjects]);
const handleInputChange = (e) => {
var { name, value } = e.target;
setValues({
...values,
[name]: value,
});
};
const handleFormSubmit = (e) => {
e.preventDefault();
props.addOrEdit(values, imageFile);
};
const handleImageAsFile = (e) => {
console.log("file image",e);
const image = e.target.files[0]
setImageAsFile(imageFile => (image))
}
return (
<form autoComplete="off" onSubmit={handleFormSubmit}>
<div className="form-group input-group">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-image"></i>
</div>
</div>
<input
className="form-control"
type="file"
name="image"
placeholder="Image"
value={values.image}
onChange={handleImageAsFile}
/>
</div>
<div className="form-row">
<div className="form-group input-group col-md-6">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-mug-hot"></i>
</div>
</div>
<input
className="form-control"
name="name"
placeholder="Name"
value={values.name}
onChange={handleInputChange}
/>
</div>
<div className="form-group input-group col-md-6">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-list-alt"></i>
</div>
</div>
<input
className="form-control"
name="category"
placeholder="Category"
value={values.category}
onChange={handleInputChange}
/>
</div>
</div>
<div className="form-group input-group">
<div className="input-group-prepend">
<div className="input-group-text">
<i className="fas fa-money-check-alt"></i>
</div>
</div>
<input
className="form-control"
name="price"
placeholder="Price"
value={values.price}
onChange={handleInputChange}
/>
</div>
<div className="form-group">
<input
type="submit"
value={props.currentId == '' ? 'Save' : 'Update'}
className="btn btn-primary btn-block"
/>
</div>
</form>
);
};
export default ProductForm;
And this is the table, which the place I showed all list of product and also Action (Edit and Delete)
import React, { useState, useEffect } from 'react';
import { Card, Button, Imgage } from 'react-bootstrap'
import ProductForm from './ProductForm';
import { DB, Storage } from '../firebase';
const Products = () => {
var [currentId, setCurrentId] = useState('');
var [productObjects, setProductObjects] = useState({});
const [ImageAsUrl, setImageAsUrl] = useState()
useEffect(() => {
DB.ref().child('products').on('value', (snapshot) => {
if (snapshot.val() != null) {
setProductObjects({
...snapshot.val(),
});
}
});
}, []);
const addOrEdit = (obj, image_url) => {
let upload = Storage.ref().child(`product-img/${image_url.name}`).put(image_url)
upload.on('state_changed',
(snapShot) => {
console.log(snapShot)
}, (err) => {
console.log(err)
}, () => {
Storage.ref('product-img').child(image_url.name).getDownloadURL()
.then(fireBaseUrl => {
DB.ref().child('products').push({ name: obj.name, image: fireBaseUrl, category: obj.category, price: obj.price }, (err) => {
if (err) console.log(err);
else setCurrentId('');
})
})
})
console.log("log imgage link", ImageAsUrl);
};
const onDelete = (id) => {
if (window.confirm('Are you sure to delete this record?')) {
DB.ref().child(`products/${id}`).remove((err) => {
if (err) console.log(err);
else setCurrentId('');
});
}
};
return (
<>
<div className="jumbotron jumbotron-fluid">
<div className="container">
<h1 className="display-4 text-center">Products Manager</h1>
</div>
</div>
<div className="row">
<div className="col-md-5">
<ProductForm {...{ currentId, productObjects, addOrEdit }} />
</div>
<div className="col-md-7">
<table className="table table-borderless table-stripped">
<thead className="thead-light">
<tr>
<th>Image</th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{Object.keys(productObjects).map((key) => (
<tr key={key}>
<td>{productObjects[key].image}</td>
<td>{productObjects[key].name}</td>
<td>{productObjects[key].category}</td>
<td>{productObjects[key].price}</td>
<td className="bg-light">
<a
type="button"
className="btn text-primary"
onClick={() => {
setCurrentId(key);
}}
>
<i className="fas fa-pencil-alt"></i>
</a>
<a
type="button"
className="btn text-danger"
onClick={() => {
onDelete(key);
}}
>
<i className="far fa-trash-alt"></i>
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</>
);
};
export default Products;
This is an Error show for me when I clicked Update icon:
Uncaught DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.
Can anyone help me with this problem? I really do not know how to fix it. Please? Your help is my pleasure
As the error explains, you can not set a value property on an input / file element. Short example:
<input type="file" value="this throws an error" />
That means, you can not "pre-populate" the input field if the user already uploaded a file. You could show the file (if it's an image) and add a delete option (e.g button) next to it.