Handling Form in Nextjs - javascript

In this code example I would like to try to do easy math (ket=name + names). The sum should be a number and displayed as “ket”. But when I type in 3 and 6 in my input fields, “ket” shows up to be 36 (and not 9).
export default function Kettenl() {
const submitContact = async (event) => {
event.preventDefault();
const names = event.target.names.value;
const name = event.target.name.value;
let ket = name + names;
alert(`So your name is ${ket}?`);
};
return (
<div className="max-w-xs my-2 overflow-hidden rounded shadow-lg">
<div className="px-6 py-4">
<div className="mb-2 text-xl font-bold">Contact us</div>
<form className="flex flex-col" onSubmit={submitContact}>
<label htmlFor="name" className="mb-2 italic">
Name
</label>
<input
className="mb-4 border-b-2"
id="name"
name="name"
type="number"
required
/>
<label htmlFor="name" className="mb-2 italic">
Names
</label>
<input
className="mb-4 border-b-2"
id="names"
name="names"
type="number"
required
/>
<button
type="submit"
className="px-4 py-2 font-bold text-white bg-blue-500 rounded-full hover:bg-blue-700"
>
Submit
</button>
</form>
</div>
</div>
);
}

That is because the values are being read as strings
'3'+'6'='36'
you should change it to this
const names = parseInt(event.target.names.value);
const name = parseInt(event.target.name.value);
Also, you are storing and accessing the values incorrectly. You should learn the basics of react before moving on to next.js.
https://reactjs.org/docs/forms.html
Read about controlled and uncontrolled inputs from the docs
So even if your app works with the aforementioned change, you shouldn't be doing it like this.

Thats because values are returned as a string by default from your target element. For inputs with type="number" you can just use the input value with e.target.names.valueAsNumber.
const submitContact = async (event) => {
event.preventDefault();
const names = event.target.names.valueAsNumber;
const name = event.target.name.valueAsNumber;
let ket = name + names;
alert(`So your name is ${ket}?`);
};

Related

Modal pop up on submit in React

I am trying to display a modal pop up on submit in a form in React. Right now, the invalid email and name modal pops up just fine. The problem is, It will not display the alternate success message if the form was submitted correctly. I also am not sure if it will persist upon successful submission, but can't get past this problem to test it out. Please let me know where I am going wrong. Thanks!!
Contact.js:
import React, { useState } from "react";
import { FaEnvelope } from "react-icons/fa";
import Modal from "./Modal";
const Contact = (props) => {
const [showModal, setShowModal] = useState();
const [enteredName, setEnteredName] = useState("");
const [enteredEmail, setEnteredEmail] = useState("");
const contactHandler = (event) => {
event.preventDefault();
if (enteredName.trim().length === 0 || enteredEmail.trim().length === 0) {
setShowModal({
title: "Invalid Input",
message: "Please enter a valid name and email",
});
return;
}
if (enteredName.trim().length > 0 || enteredEmail.trim().length > 0) {
setShowModal({
title: "Thank You",
message: "Your form as been submitted",
});
return;
}
props.Contact(enteredName, enteredEmail);
setEnteredName("");
setEnteredEmail("");
};
const modalHandler = () => {
setShowModal(null);
};
return (
<div>
{showModal && (
<Modal
title={showModal.title}
message={showModal.message}
onShowModal={modalHandler}
/>
)}
<div className="w-full h-screen main flex justify-center items-center p-4">
<form
onSubmit={contactHandler}
method="POST"
action="https://getform.io/f/8e30048c-6662-40d9-bd8b-da62595ce998"
className="flex flex-col max-w-[600px] w-full"
>
<div className="pb-8">
<p className="text-4xl font-bold inline border-b-4 bdr text-main">
Contact
</p>
<span>
<FaEnvelope className="inline-flex ml-4 text-4xl text-main" />
</span>
<p className="text-main py-2">
Please enter your info below and I will be back with you within 24
hours. You can also email me directly at:
<a
href="mailto:chris.t.williams417#gmail.com"
className="ml-2 font-bold hover:text-[#FFE5b4]"
>
chris.t.williams417#gmail.com
</a>
</p>
</div>
<input
className="form-bg p-2"
type="text"
placeholder="Name"
name="name"
/>
<input
className="my-4 py-2 form-bg"
type="email"
placeholder="Email"
name="email"
/>
<textarea
className="form-bg p-2"
name="message"
rows="10"
placeholder="Message"
></textarea>
<button className="con-btn">Submit</button>
</form>
</div>
</div>
);
};
export default Contact;
Modal.js:
import React from "react";
const Modal = (props) => {
return (
<div>
<div className="backdrop" onClick={props.onShowModal} />
<div className="modalPos">
<div className="header">
<h2>{props.title}</h2>
</div>
<div className="content">
<p>{props.message}</p>
</div>
<div className="actions">
<button onClick={props.onShowModal} className="hero-btn">
Exit
</button>
</div>
</div>
</div>
);
}
export default Modal
*disclaimer : my grammar so bad so i am apologize about that.
i just try your code and when i submit is always invalid, i check it and the state name and email is empty string when i submit because your forgot implement onChangeHanlde in input.
create function to handle onChange
const onChangeHandler = (field, event) => {
if (field == "email") {
setEnteredEmail(event.target.value);
} else if (field == "name") {
setEnteredName(event.target.value);
}
};
and add onChange, value attribute in input tag both name and email
<input
className="form-bg p-2"
type="text"
placeholder="Name"
name="name"
onChange={(e) => {
onChangeHandler("name", e);
}}
value={enteredName}
/>
<input
className="my-4 py-2 form-bg"
type="email"
placeholder="Email"
name="email"
onChange={(e) => {
onChangeHandler("email", e);
}}
value={enteredEmail}
/>
You didn't put
value = {enteredName}
in your input element. so your states will not be set by user's input.

React - "Functions are not valid as a React child" when I return text from a function

I am learning React.js and I am not sure what is happening here. I want to have a function that returns a string isWaterBoiling() depending on the value of a variable. Then I want to render that string in UI but I am getting this error. I dont understand why this is happening, it doesnt make sense:
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
at div
Here is my code:
import { useState } from "react"
const App = () => {
const [celsius, setCelsius] = useState()
const [fahrenheit, setFahrenheit] = useState()
const calculateFahrenheit = newCelsius => {
setCelsius(newCelsius)
setFahrenheit(((newCelsius * 9 / 5) + 32).toFixed(2))
}
const calculateCelsius = newFahrenheit => {
setFahrenheit(newFahrenheit)
setCelsius(((newFahrenheit - 32) * 5 / 9).toFixed(2))
}
const isWaterBoiling = () => {
return (parseFloat(celsius >= 100))
? "boiling"
: "not boiling"
}
return (
<div className="bg-gray-800 h-full text-gray-300 p-4 text-center">
<div className="font-semibold">Temperature Calculator</div>
<div className="mt-4 space-y-4">
<div className="flex gap-3 items-center">
<span className="flex-[5] text-right">Celsius:</span>
<input
value={celsius}
onChange={event => calculateFahrenheit(event.target.value)}
className="flex-[7] bg-gray-700 rounded-sm py-1 px-3"
type="text"
/>
</div>
<div className="flex gap-3 items-center">
<span className="flex-[5] text-right">Fahrenheit:</span>
<input
value={fahrenheit}
onChange={event => calculateCelsius(event.target.value)}
className="flex-[7] bg-gray-700 rounded-sm py-1 px-3"
type="text"
/>
</div>
</div>
<div className="mt-4 italic text-gray-400">
The water is { isWaterBoiling }
</div>
</div>
)
}
export default App
As the error mentions, you are not calling your isWaterBoiling function, but returning it. You need to change that bit of code to The water is { isWaterBoiling() }

How to get parent div in handleChange with React

I have multiple divs that are dynamic (it depends on which filter the visitor checked). So I can not use getElementById.
I need to get the parent div to change its CSS if an input is checked.
Here is my code:
{workout?.map(x => {
return <div className='relative bg-gray-200 p-4 rounded-md my-3 mx-2' key={x.name}>
<input onClick={handleChecked} className='absolute right-0 top-0' type="checkbox" />
<div className='flex'>
<img className='w-2/6 rounded mr-5' src={`${x.path}`} alt={x.name} />
<div className='w-4/6'>
<h2 className='text-xl'>{x.name}</h2>
<p>Nombre de séries : {x.set}</p>
<p>Nombre de rép : {x.reps}</p>
{x.secondary ? <p>Muscles solicités : <br />
<span className='space-x-2'>
{x?.secondary?.map(k => {
return <span className='bg-white px-1 rounded-md' key={k}>{k}</span>
})}
</span>
</p> : null}
</div>
</div>
</div>
})}
The idea, is to add a border-2 border-teal-500 class to the parent div of the input when it is checked.
Here is my handleChecked:
function handleChecked(e) {
// code here
}
I saw that I had to use parentNode but the problem is, I can't store in a variable the current input because it is dynamic. Every item has its own input.
Any idea how I can handle this?
You shouldn't be using getElementById (or any other vanilla JS DOM method) in React anyway - store and change values in state instead. You can leverage this by making input a controlled component, and storing the checked values in an array, or in workout - then, when returning the JSX, you just need to check whether the x variable (the item being iterated over) indicates that the current input should be checked or not - which will also tell you whether the parent should have a different class.
const makeHandleChecked = (i) => (e) = {
setWorkout(
workout.map(
(w, j) => j !== i ? w : { ...w, checked: e.target.checked }
)
);
};
{workout?.map((x, i) => (
<div className={`relative bg-gray-200 p-4 rounded-md my-3 mx-2${x.checked ? ' checked' : ''}`} key={x.name}>
<input onClick={makeHandleChecked(i)} checked={x.checked} className='absolute right-0 top-0' type="checkbox" />

setting the value of more than one input

I am trying to build a login form. I am trying to set up the value of the email & password field individually. But as soon as I try to enter the text in the email text field, the same appears in the password field too. Can I have a solution to this?
Below is the code.
I guess the error is in OnChange fn where I am assigning the same value e.target.value to both the {email, passwaord}.
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
const LoginPage = () => {
let navigate = useNavigate();
const [credentials, setCredentials] = useState({email:"",password:""});
const onChange = (e) => {
setCredentials({email: e.target.value ,password: e.target.value})
console.log(credentials.email, credentials.password)
}
const goToSignUp = () => {
navigate("/signup");
}
return (
<>
<div className="container my-5">
<div id="loginbody">
<div className="mt-3">
<h2 className="my-3 display-3">Login Here</h2>
<form className="login-form p-5">
<div className="mb-3">
<label for="exampleInputEmail1" className="form-label">
Email address
</label>
<input
type="email"
className="form-control"
id="email"
name="email"
value={credentials.email}
aria-describedby="emailHelp"
onChange={onChange}
/>
<div id="emailHelp" className="form-text">
We'll never share your email with anyone else.
</div>
</div>
<div className="mb-3">
<label for="exampleInputPassword1" className="form-label">
Password
</label>
<input
type="password"
className="form-control"
id="password"
name="password"
value={credentials.password}
onChange={onChange}
/>
</div>
<div className="d-grid gap-2 my-4 col-6 mx-auto">
<button type="submit" className="btn btn-success">
Submit
</button>
</div>
<hr />
<div className="mb-3 text-center">
<div id="emailHelp" className="form-text center my-3">
Didn't have an account ?
</div>
<div className="d-grid gap-2 my-3 col-6 mx-auto">
<button onClick={goToSignUp} className="btn btn-success ">
SignUp Here !
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</>
);
};
export default LoginPage;
You have identified the problem. You need to pass the key to change as well.
Here passing a callback to setState which provides the current state as a parameter, cloning the state object using spread syntax, and then updating the relevant property in the copied object using the passed key as a computed property name.
const LoginPage = () => {
const [credentials, setCredentials] = useState({email:"",password:""});
const onChange = (e, key) => {
setCredentials(prevCredentials => ({...prevCredentials, [key]: e.target.value}))
}
return (
<>
//...
<input
type="email"
className="form-control"
id="email"
name="email"
value={credentials.email}
aria-describedby="emailHelp"
onChange={(e) => onChange(e, 'email')}
/>
//...
<input
type="password"
className="form-control"
id="password"
name="password"
value={credentials.password}
onChange={(e) => onChange(e, 'password')}
/>
//...
</>
);
};
Note: Calling console.log() right after setting state will not log the updated state, the new state values won't be available until the next render cycle. see: useState set method not reflecting change immediately
Use the proper key to the respective fields
const onChange = (e) => {
setCredentials({ ...credentials, [e.target.name]: e.target.value})
console.log(credentials);
}

Cannot use/update input value in react hooks which will be added to an image src attribute from a random image generator url

I have built a form with 2 inputs and I can get the input value using react-hook-form package but then i cannot update the state value with input value which i need to put inside an image src url end-point so that every time i submit the form i can get image width & height value and generate a random image. by the way i am using Lorem Picsum auto image generator but it's not working or i might be doing it wrong way and also getting error!..let me understand what's going on...Thank you very much.. :-)
// Here's the full code - no props coming from any other components
import React, { useState } from "react";
import { useForm } from "react-hook-form";
const ImageGenerator = () => {
const { register, handleSubmit } = useForm();
const [firstInput, setFirstInput] = useState([]);
const [secondInput, setSecondInput] = useState([]);
const handleInput = (value) => {
let firstValue = value.firstInput;
let secondValue = value.secondInput;
setFirstInput({ firstInput: firstValue });
setSecondInput({ secondInput: secondValue });
};
return (
<React.Fragment>
<form onSubmit={handleSubmit(handleInput)}>
<div className="form-row">
<div className="col-5 mt-4">
<label htmlFor="firstInput" className="font-weight-500">
Set Width
</label>
<input
type="number"
name="firstInput"
className="form-control"
id="firstInput"
ref={register}
/>
</div>
<div className="col-5 mt-4">
<label htmlFor="secondInput" className="font-weight-500">
Set Height
</label>
<input
type="number"
name="secondInput"
className="form-control"
id="secondInput"
ref={register}
/>
</div>
<div className="col-2 mt-5">
<button
type="submit"
className="btn btn-primary"
style={{ marginTop: "7px" }}
>
Generate
</button>
</div>
</div>
</form>
<div className="row">
<img
src={`https://picsum.photos/${firstInput}/${secondInput}`}
alt=""
/>
</div>
</React.Fragment>
);
};
export default ImageGenerator;
why did you use array in useState()?
const [firstInput, setFirstInput] = useState([]);
const [secondInput, setSecondInput] = useState([]);

Categories

Resources