onClick event is undifned - reactjs

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.

Related

React <input> value will not change when edit

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

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
}

How do I revert input values back to default values onClick in React?

I have a data table built in react hooks. On each row I'm allowing the user to edit the values and enter what I'm calling edit mode seen below:
enter const TableRow = (props: any) => {
const [inputs, setInputs] = useState({});
const [editMode, setEditMode] = useState(false)
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setInputs(prevState => ({ ...prevState, [event.target.name]: event.target.value }));
}
const onStartEdit = () => setEditMode(true)
const onEditCommit = (event: MouseEvent<HTMLButtonElement>) => {
// console.log('on edit inputs: ', inputs)
// props.updateRow(inputs, props.id)
}
const onCancelEditMode = () => setEditMode(false)
return (
<tr>
<td>
<input
disabled={!editMode}
name="merchant"
placeholder="Merchant Name"
type="text"
onChange={handleChange}
defaultValue={props.row.merchant}
/>
</td>
<td>
<input
disabled={!editMode}
name="item"
placeholder="Item"
type="text"
onChange={handleChange}
defaultValue={props.row.item}
/>
</td>
<td>
{props.row.amtCrypto}
</td>
<td>
<input
disabled={!editMode}
name="currency"
placeholder="Currency"
type="text"
onChange={handleChange}
defaultValue={props.row.currency}
/>
</td>
<td>
{props.row.cryptoPrice}
</td>
<td>
<input
disabled={!editMode}
name="amount"
placeholder="Amount(USD)"
type="text"
onChange={handleChange}
defaultValue={props.row.amount}
/>
</td>
<td>
{!editMode &&
<div>
<button
onClick={onStartEdit}
>
Edit
</button>
<button
onClick={onDeleteRow}
>
Delete Row
</button>
</div>
}
{editMode &&
<div>
<button
onClick={onEditCommit}
>
Complete
</button>
<button
onClick={onCancelEditMode}
>
Cancel
</button>
</div>}
</td>
</tr>
)
}
So basically on startEditMode I am making the fields editable and on cancelEditMode I'd like to lock the fields and revert them back to the default values. How would I implement this?
First you can put the initial values received from props in the inputs state
const [inputs, setInputs] = useState({merchant: props.row.merchant, ...});
You should use the value of the inputs state as single source of truth.
<input
disabled={!editMode}
name="merchant"
placeholder="Merchant Name"
type="text"
onChange={handleChange}
value={inputs.merchant}
/>
When the onCancelEditMode function gets called you can set the input state with the initial values from props
const onCancelEditMode = () => {
setEditMode(false)
setInput({merchant: props.row.merchant, ...})
}

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,
),
)
}

Clear form after submit React

In my app, I am making a form to add animal for adoption with React. The data is stored in Mongo if this is important to know.
But I can not figure out how, I tried to look and nothing works for me. Maybe there is something wrong with the form. I would be very thankful if someone can tell me how to clear or reset the form after submitting. I simplified it so it would be easy to see what I have. Here is my form:
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { addAnimal } from "../redux/actions";
const AddAnimalForm = () => {
const dispatch = useDispatch();
const [name, setName] = useState("");
const [kind, setKind] = useState("");
const [displayForm, setDisplayForm] = useState(false);
const dispatchAddAnimal = () => {
dispatch(
addAnimal(
{
name,
kind
},
"_id name kind sex age city author phone info"
)
);
};
const onShowButtonClicked = () => {
setDisplayForm(true);
};
const onHideButtonClicked = () => {
setDisplayForm(false);
};
return !displayForm ? (
<button className="col-xs-12 col-md-3" onClick={onShowButtonClicked}>
add
</button>
) : (
<React.Fragment>
<div className="col-xs-12 col-sm-9">
<button className="col-xs-12 col-md-3" onClick={onHideButtonClicked}>
hide{" "}
</button>
<form>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="animal-name">name</label>
<input
type="text"
className="form-control"
onChange={e => setName(e.target.value)}
id="animal-name"
/>
</div>
<div className="form-group col-md-6">
<label htmlFor="kind">kind</label>
<input
type="text"
onChange={e => setKind(e.target.value)}
className="form-control"
id="kind"
/>
</div>
</div>
<button
type="button"
className="btn btn-primary"
onClick={dispatchAddAnimal}
>
add animal
</button>
</form>
</div>
</React.Fragment>
);
};
export default AddAnimalForm;
define a variable at the top just below you imports
let exampleRef = React.createRef()
hi first you have to create a reference to that form like this :-
<form ref={(el) => myFormRef = el;}>
<input />
<input />
...
<input />
</form>
and after that, while submitting your form you just use the reset() method provided by the form reference like this
const dispatchAddAnimal = () => {
myFormRef.reset();
dispatch(
addAnimal(
{
name,
kind
},
"_id name kind sex age city author phone info"
)
);
};
let me know if it works for you or not.
there is also a great library React Advanced Form which handle lots of thing on its own like validation and other stuff check this out if you feel free

Resources