React <input> value will not change when edit - reactjs

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/>

Related

How do I pass data to the backend using Reactjs?

The backend is working properly with the Postman. but it not working correctly with my front end. This error occurs when I try to add a product. I used the Axios to send HTTP requests from the frontend to the backend. Please can you help me solve this error
Access to XMLHttpRequest at 'http://localhost:8070/products/' from origin 'http://localhost:1234' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This is my AddProduct.js file.
import axios from "axios";
import React, { useState } from "react";
export default function AddProduct() {
const [name, setName] = useState();
const [description, setDescription] = useState();
const [qty, setQty] = useState(0);
const [price, setPrice] = useState(0);
const handleSubmit = async (e) => {
e.preventDefault();
const data = {
name,
description,
qty,
price,
};
console.log("data", data);
const insert = await axios
.post("http://localhost:8070/products/", data)
.then(() => {
alert("Product Added successfully");
e.target.reset();
})
.catch((err) => {
alert("Failed: " + err.message);
});
};
return (
<div className="p-5 m-5">
<form onSubmit={handleSubmit}>
<div className="mb-3">
<label className="form-label">Name</label>
<input
type="text"
className="form-control"
onChange={(e) => setName(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Description</label>
<textarea
className="form-control"
onChange={(e) => setDescription(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Quantity</label>
<input
type="number"
className="form-control"
onChange={(e) => setQty(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Price</label>
<input
type="number"
className="form-control"
onChange={(e) => setPrice(e.target.value)}
/>
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
</div>
);
}
This is my AllProduct.js file.
import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
export default function AllProduct() {
const [product, setProduct] = useState();
const navigate = useNavigate();
var sum;
useEffect(() => {
axios
.get(`http://localhost:8070/products/`)
.then((res) => {
setProduct(res.data);
})
.catch((err) => {
alert("Failed: " + err.message);
});
}, []);
console.log(product);
const handleDelete = async (id) => {
let ans = window.confirm("Do you want to delete this product ?");
if (ans) {
await axios
.delete(`http://localhost:8070/products/${id}`)
.then(() => {
alert("Delete Successfully");
window.location.reload(false);
})
.catch((err) => {
alert("Failed: " + err.message);
});
}
};
const handleEdit = (product) => {
let { _id, name, description, qty, price } = product;
console.log("product", product);
localStorage.setItem("pID", _id);
localStorage.setItem("pName", name);
localStorage.setItem("pDescription", description);
localStorage.setItem("pQty", qty);
localStorage.setItem("pPrice", price);
navigate("/edit");
};
return (
<div className="p-5 m-5">
<table className="table">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th scope="col">Quantity</th>
<th scope="col">Price</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{product?.map((product, index) => (
<tr key={index}>
<th scope="row">{index + 1}</th>
<td>{product.name}</td>
<td>{product.description}</td>
<td>{product.qty}</td>
<td>{product.price}</td>
<td>
<button
className="btn btn-danger"
onClick={() => handleDelete(product._id)}
>
Delete
</button>
</td>
<td>
<button
className="btn btn-warning"
onClick={() => handleEdit(product)}
>
Edit
</button>
</td>
</tr>
))}
</tbody>
</table>
{
(sum = product
?.map((product) => Number(product.price.replace("$", "")))
.reduce((prev, curr) => prev + curr, 0))
}
</div>
);
}
This is my editProduct.js
import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
export default function EditProduct() {
const navigate = useNavigate();
const [id, setId] = useState();
const [name, setName] = useState();
const [description, setDescription] = useState();
const [qty, setQty] = useState();
const [price, setPrice] = useState();
useEffect(() => {
setId(localStorage.getItem("pID"));
setName(localStorage.getItem("pName"));
setDescription(localStorage.getItem("pDescription"));
setQty(localStorage.getItem("pQty"));
setPrice(localStorage.getItem("pPrice"));
}, []);
const handleUpdate = (e) => {
e.preventDefault();
const updateData = {
name,
description,
qty,
price,
};
console.log("id 27 ", id);
axios
.put(`http://localhost:8070/products/${id}`, updateData)
.then(() => {
alert("Product Update");
navigate("/all");
})
.catch((err) => {
alert(err);
});
};
return (
<div className="p-5 m-5">
<form onSubmit={handleUpdate}>
<div className="mb-3">
<label className="form-label">Name</label>
<input
type="text"
className="form-control"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Description</label>
<textarea
className="form-control"
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Quantity</label>
<input
type="number"
className="form-control"
value={qty}
onChange={(e) => setQty(e.target.value)}
/>
</div>
<div className="mb-3">
<label className="form-label">Price</label>
<input
type="number"
className="form-control"
value={price}
onChange={(e) => setPrice(e.target.value)}
/>
</div>
<button type="submit" className="btn btn-warning" href="/all">
update
</button>
</form>
</div>
);
}
This error is a CORS Policy, or to be specific, Cross-Origin Resource Sharing,
What you need to do, assuming you are using nodejs express, is this couple of lines in the app.js module.
install cors
npm i cors
const cors = require("cors");
server.use(cors({ origin: "http://localhost:8070" }));
This will enable data-transfer between the FE and the BE.
you need to setup cors options on your server. If its a node server i recommend this library https://www.npmjs.com/package/cors everything is explained on the documentation.
on setup you need allow your frontend url which is http://localhost:1234

onClick event is undifned

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.

How to get data out of react-hook-form?

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
}

update input of user in map function React hooks

New to react hooks...
I've brought some data of users from an API and I want to update one or more of the inputs by clicking a submit button.
I can see in the state that the user's last letter changes but I can see the new input on the screen and I can not change the entire word. And I don't know if it is supposed to change also in the whole array of users or it is impossible once I've called them from the API.
Thanks
import { useState } from 'react'
import axios from 'axios'
function UsersComp() {
const [user, setUser] = useState()
const [users, setUsers] = useState([])
const [id, setId] = useState(0)
const getUsers=async ()=>{
let resp = await axios.get("https://jsonplaceholder.typicode.com/users")
setUsers(resp.data);
}
const update = async (e) =>
{
e.preventDefault();
let resp = await axios.put("https://jsonplaceholder.typicode.com/users/" + id, user)
}
return (
<div calssname="App">
<form onSubmit={e => update(e)}>
{
users.map((item) =>
{
return <tbody key={item.id}>
<tr><td>
ID:{item.id} <br/>
Name:<input value={item.name} onChange={e => setUser({...user, name : e.target.value})} type="text" name="name" /> <br/>
Email:<input value={item.email} onChange={e => setUser({...user, email : e.target.value})} type="text" name="email" /> <br/>
<input type="button" value="Add Data"/>
<input type="submit" value="Update"/>
<input type="button" value="Delete"/><br/>
</td></tr>
</tbody>
})
}
</form>
<input type="button" value="Get users" onClick={getUsers} /> <br/>
</div>
);
}
export default UsersComp;
You can update onChange like this by using map:
onChange={(e) =>
setUser(
users.map((eachUser) =>
item.id === eachUser.id ? { ...eachUser, name: e.target.value } : eachUser,
),
)
}

How to add checkbox or radio button inside the map method in react component?

How to add the checkbox or radio button inside the map method. I have created question and answer app. I need to add checkbox or radio button for the answers. Below in the card component is where the question and answer is getting printed out. How can i add the radio button in there so user can check the answer.
import React, { useState, useEffect } from "react";
import { Fragment } from "react";
import "./Survey.css";
import CreateSurvey from "../modals/CreateSurvey";
import Card from "../card/Card";
const Survey = () => {
const [modal, setModal] = useState(false);
const [surveyList, setSurveyList] = useState([]);
useEffect(() => {
let arr = localStorage.getItem("surveyList");
if (arr) {
let obj = JSON.parse(arr);
setSurveyList(obj);
}
}, []);
const deleteSurvey = (index) => {
let tempList = surveyList;
tempList.splice(index, 1);
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(tempList);
window.location.reload();
};
const toggle = () => {
setModal(!modal);
};
const updateListArray = (obj, index) => {
let tempList = surveyList;
tempList[index] = obj;
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(tempList);
window.location.reload();
};
const saveSurvey = (surveyObj) => {
let tempList = surveyList;
tempList.push(surveyObj);
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(surveyList);
setModal(false);
};
return (
<Fragment>
<div className="header text-center">
<h5>Survey</h5>
<button className="btn btn-primary" onClick={() => setModal(true)}>
Create Survey
</button>
</div>
<div className="survey-container">
{surveyList &&
surveyList.map((obj, index) => (
<Card
surveyObj={obj}
index={index}
deleteSurvey={deleteSurvey}
updateListArray={updateListArray}
/>
))}
</div>
<CreateSurvey toggle={toggle} modal={modal} save={saveSurvey} />
</Fragment>
);
};
export default Survey;
//Card.js
import React, { useState } from "react";
import "./Card.css";
const Card = ({ surveyObj, deleteSurvey, index }) => {
const [modal, setModal] = useState(false);
const toggle = () => {
setModal(!modal);
};
const deleteHandler = () => {
deleteSurvey(index);
};
return (
<div>
<div className="card-wrapper mr-5">
<div className="card-top"></div>
<div className="survey-holder">
<span className="card-header">{surveyObj.name}</span>
<p className="answer"> {surveyObj.answerOne}</p>
<div className="icons">
<i className="far fa-edit edit"></i>
<i className="fas fa-trash-alt delete" onClick={deleteHandler}></i>
</div>
</div>
</div>
</div>
);
};
export default Card;
//Createsurvey.js
import React, { useState } from "react";
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import { Fragment } from "react";
const CreateSurvey = ({ modal, toggle, save }) => {
const [question, setQuestion] = useState("");
const [answerOne, setAnswerOne] = useState("");
const [answerTwo, setAnswerTwo] = useState("");
const [answerThree, setAnswerThree] = useState("");
const [answerFour, setAnswerFour] = useState("");
const changeHandler = (e) => {
const { name, value } = e.target;
if (name === "question") {
setQuestion(value);
} else {
setAnswerOne(value);
}
};
const saveHandler = (e) => {
e.preventDefault();
let surveyObj = {};
surveyObj["name"] = question;
surveyObj["answerOne"] = answerOne;
surveyObj["answerTwo"] = answerTwo;
surveyObj["answerThree"] = answerThree;
surveyObj["answerFour"] = answerFour;
save(surveyObj);
};
return (
<Fragment>
<Modal isOpen={modal} toggle={toggle}>
<ModalHeader toggle={toggle}>Create a Survey Question</ModalHeader>
<ModalBody>
<form>
<div>
<div className="form-group">
<label>Survey Questions</label>
<input
type="text"
className="form-control"
value={question}
name="question"
onChange={changeHandler}
/>
</div>
</div>
<div className="mt-2">
<label>Survey Answers</label>
<div className="form-group">
<label>Answer 1</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerOne}
name="answerOne"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 2</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerTwo}
name="answerTwo"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 3</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerThree}
name="answerThree"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 4</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerFour}
name="answerFour"
onChange={changeHandler}
/>
</div>
</div>
</form>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={saveHandler}>
Create
</Button>
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
</Fragment>
);
};
export default CreateSurvey;
What I am understanding is that you want to add multiple component in map method. You can simply do it as:
{surveyList &&
surveyList.map((obj, index) => (
<>
<Card
surveyObj={obj}
index={index}
deleteSurvey={deleteSurvey}
updateListArray={updateListArray}
/>
<input type="checkbox" name="userchoice" />
</>
))}

Resources