react-phone-number-input code sample using http API - reactjs

Just asking how to get this and put it to my API. Here's a link: https://web.5writer.com/user/signup
{
"countryCallingCode": "374",
"nationalNumber": "23131223",
"number": "+37423131223",
"country": "AM"
}
This is the body of my API
{
dial_code,
mobile,
iso_code
}
This is my code
export default function Home() {
const toast = useToast()
const router = useRouter();
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const [dial_code, setDial] = useState('');
const [mobile, setMobile] = useState('');
const [iso_code, setIso] = useState('');
async function handleSubmit (e) {
e.preventDefault();
setLoading(true);
fetch(`https://web.5writer.com/user/signup`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
dial_code,
mobile,
iso_code,
}),
})
.then((res) =>
res.json().then((body) => ({
status: res.status,
body,
}))
)
.then((resp) => {
console.log(resp);
setLoading(false);
if (resp.body.status === true) {
setDial('');
setMobile('');
setIso('');
toast({
title: 'Success!',
description: resp.body.message,
status: 'success',
duration: 6000,
isClosable: true,
position: 'top',
variant: 'left-accent',
});
router.push('../AllOrders/dashboard');
}
else {
toast({
title: 'ERROR!',
description: resp.body.message,
status: 'error',
duration: 6000,
isClosable: true,
position: 'top',
variant: 'left-accent',
});
}
})
}
return (
<div>
{success && <Notification />}
<main>
<Container >
<Box
w='17.8em'
p={0}
borderRadius='5px'
mt={3}
mb={-4}
mx='auto'
pos='relative'
marginLeft='-1em'
>
{loading && (
<Progress
pos='absolute'
top='0'
left='0'
width='100%'
isIndeterminate
borderTopLeftRadius='6px'
borderTopRighRtadius='6px'
size='sm'
colorScheme='blue'
/>
)}
<form onSubmit={handleSubmit}>
<FormControl className="">
<PhoneNumber
placeholder="enter phone number"
value={dial_code}
onChange={(e) => setDial(e.target.value)}
/>
</FormControl>
<div className="form-group2 d-md-flex">
<div className="w-50 text-left">
<input type="checkbox" className="checkL"/>
<div className="remember">
I have read the <a className="terms">Terms and Condition</a>
</div>
</div>
</div>
<Button
type='submit'
mt='0'
size='sm'
colorScheme='#2CBEFF'
disabled={loading}
pos='relative'
className="lbutton"
>
Register
{/* {loading && <Spinner pos='absolute' color='red.500' />} */}
</Button>
<div className="form-group3">
<p className="text-center">Already have an account?
<Link href="/Login"><a data-toggle="tab" className="Log">Log In</a></Link></p>
</div>
</form>
</Box>
</Container>
</main>
</div>
);
}
This code is working but the problem is I only got one data using onChange. Is it possible to use 3 onChange? or is there any method to get 3 data in just one input.
Give me a piece of advice thank you.

It's still not entirely clear what your issue is, but based on the comments it seems you want a single state variable and change handler to manage 3 inputs. You generally accomplish this by associating a name attribute with each input. The name attribute is accessed via the onChange event and can update the specific nested state.
Example:
const initialState = {
country: "",
countryCallingCode: "",
number: ""
};
function App() {
const [{ country, countryCallingCode, number }, setState] = React.useState(
initialState
);
const changeHandler = (e) => {
const { name, value } = e.target; // <-- destructure from event
setState((state) => ({
...state,
[name]: value // <-- use name as dynamic key
}));
};
const submitHandler = (e) => {
e.preventDefault();
const data = {
dial_code: countryCallingCode,
number,
country
};
setState(initialState);
console.log(data);
};
return (
<div className="App">
<form onSubmit={submitHandler}>
<div>
<label>
Country Code
<input
type="text"
value={countryCallingCode}
name="countryCallingCode"
onChange={changeHandler}
/>
</label>
</div>
<div>
<label>
Number
<input
type="text"
value={number}
name="number"
onChange={changeHandler}
/>
</label>
</div>
<div>
<label>
Country
<input
type="text"
value={country}
name="country"
onChange={changeHandler}
/>
</label>
</div>
<button type="submit">Submit</button>
</form>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<App />,
rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />
Update
If you want to use the PhoneInput component you need to map its onChange handler to your own since it passes directly the input value to the handler.
const changeHandler = (e) => {
const { name, value } = e.target;
setState((state) => ({
...state,
[name]: value
}));
};
Here the changeHandler is expecting an onChange event object. You can pass any object you like, and so long as it has the correct shape and properties the handler can handle it.
<PhoneInput
value={number}
name="number"
onChange={(value) =>
changeHandler({
target: {
name: "number",
value
}
})
}
/>
Update 2
Ok, I think I understand what you're after now. You want just a single phone number input and then to parse the country code, country, and phone number from the single state.
Check parsePhoneNumber
There's no need for any custom onChange handlers, just update state with the PhoneInput value and when you are ready, parse the state.
const [state, setState] = React.useState(null);
const submitHandler = (e) => {
e.preventDefault();
const {
countryCallingCode: dial_code,
country: iso_code,
number: mobile
} = parsePhoneNumber(state);
const data = {
dial_code,
mobile,
iso_code
};
setState(null);
// do with data now what you need
};
...
<PhoneInput value={state} onChange={setState} />

hi that's a little dirty but you can create your state somethings like this
let [values,setValues] = useState({phoneNumber : '', dial:'', code:''});
let [inputState, setInputState] = useState('phoneNumber');
const onInputChange = (e) => {
const { target : { value } } = e;
setValues(preventValues => ({...preventValues, inputState : value}))
}
const handleSubmit = (inputStateName) => {
// do your functionality then
setInputState(inputStateName);
}

Related

how to get value in dynamic input to sql React

I'm a newbie react.I had generated input fields dynamically. Now I want to get values firstName and Lastname in this dynamics input fields to the database but I don't know how to get this value.
please help me
his my code App.js
import React, { useState } from "react";
function App() {
const [inputList, setInputList] = useState([{ firstName: "", lastName: "" }]);
const handleInputChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleAddClick = () => {
setInputList([...inputList, { firstName: "", lastName: "" }]);
};
return (
<div className="App">
{inputList.map((x, i) => {
return (
<div className="box">
<input
name="firstName"
placeholder="Enter First Name"
value={x.firstName}
onChange={e => handleInputChange(e, i)}
/>
<input
className="ml10"
name="lastName"
placeholder="Enter Last Name"
value={x.lastName}
onChange={e => handleInputChange(e, i)}
/>
<div className="btn-box">
{inputList.length - 1 === i && <button onClick={handleAddClick}>Add</button>}
</div>
</div>
);
})}
<div style={{ marginTop: 20 }}>{JSON.stringify(inputList)}</div>
</div>
);
}
export default App;
Thank you
You need to retrieve values from server side which means you will do fetch process in browser side. Use useEffect to do fetch call and set the response with setInputList.
The below is one way with useEffect. Depending on your pj concept, you can also use useSwr, SSR or etc where data retrieving happens.
import React, { useState, useEffect } from "react";
function App() {
const [inputList, setInputList] = useState([{ firstName: "", lastName: "" }]);
const handleInputChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleAddClick = () => {
setInputList([...inputList, { firstName: "", lastName: "" }]);
};
useEffect(()=>{
let canExexute = true;
// Anything to retrieve data such as
// fetch, graphql query,,,etc
// Set values from the above
if (canExecute) setInputList(values)
// Caring about when unmounting component
return ()=>{
canExecute = false;
}
// Don't put inputList state itself as dependancies which causes infinite rendering.
},[dependencies])
return (
<div className="App">
{inputList.map((x, i) => {
return (
<div className="box">
<input
name="firstName"
placeholder="Enter First Name"
value={x.firstName}
onChange={e => handleInputChange(e, i)}
/>
<input
className="ml10"
name="lastName"
placeholder="Enter Last Name"
value={x.lastName}
onChange={e => handleInputChange(e, i)}
/>
<div className="btn-box">
{inputList.length - 1 === i && <button onClick={handleAddClick}>Add</button>}
</div>
</div>
);
})}
<div style={{ marginTop: 20 }}>{JSON.stringify(inputList)}</div>
</div>
);
}
export default App;

Losing focus on input onChange React

What I'm trying to achieve, it's to create each input as own component.
And I can't get how to fix thing when my app all the time rerendering when I'm pressing any key.
I know if I'll use controlledInputs -> so each input would have it own useState that would work. But the main idea to do that this way
import React, { useState } from 'react';
const ControlledInputs = () => {
const [person, setPerson] = useState({ firstName: '', email: '', age: '' });
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
if (person.firstName && person.email && person.age) {
const newPerson = { ...person, id: new Date().getTime().toString() };
setPeople([...people, newPerson]);
setPerson({ firstName: '', email: '', age: '' });
}
};
function FormControl({number, idname , type , text}){
return(
<div className='form-control'>
<label htmlFor={idname}>{text} : </label>
<input
type={type}
id={idname}
name={idname}
value={person[idname]}
onChange={(e) =>handleChange(e)}
/>
</div>
)
}
return (
<>
<article className='form'>
<form>
<FormControl idname={"firstName"} type={"text"} text={"First name"}/>
<FormControl type={"email"} idname={"email"} text={"Email"}/>
<FormControl type={"age"} idname={"age"} text={"Age"}/>
<button type='submit' className='btn' onClick={handleSubmit}>
add person
</button>
</form>
</article>
<article>
{people.map((person) => {
const { id, firstName, email, age } = person;
return (
<div key={id} className='item'>
<h4>{firstName}</h4>
<p>{email}</p>
<p>{age}</p>
</div>
);
})}
</article>
</>
);
};
export default ControlledInputs;
You need to define the FormControl outside of ControlledInputs, otherwise, React will recreate it and you lose focus as well as data.
And you need to pass value and handleChange as props in FormControl.
Here are codes you can refactor. Please note that the number you defined is not removed.
function FormControl({value, handleChange, idname , type , text}){
return(
<div className='form-control'>
<label htmlFor={idname}>{text} : </label>
<input
type={type}
id={idname}
name={idname}
value={value}
onChange={(e) =>handleChange(e)}
/>
</div>
)
}
Usage in form:
function FormControl({value, handleChange, idname , type , text}){
return(
<div className='form-control'>
<label htmlFor={idname}>{text} : </label>
<input
type={type}
id={idname}
name={idname}
value={value}
onChange={(e) =>handleChange(e)}
/>
</div>
)
}
const ControlledInputs = () => {
const [person, setPerson] = useState({ firstName: '', email: '', age: '' });
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
if (person.firstName && person.email && person.age) {
const newPerson = { ...person, id: new Date().getTime().toString() };
setPeople([...people, newPerson]);
setPerson({ firstName: '', email: '', age: '' });
}
};
return (
<>
<article className='form'>
<form>
<FormControl idname={"firstName"} type={"text"} text={"First name"} value={person['firstName']} handleChange={handleChange}/>
<FormControl type={"email"} idname={"email"} text={"Email"} value={person['email']} handleChange={handleChange}/>
<FormControl type={"age"} idname={"age"} text={"Age"} value={person['age']} handleChange={handleChange}/>
<button type='submit' className='btn' onClick={handleSubmit}>
add person
</button>
</form>
</article>
<article>
{people.map((person) => {
const { id, firstName, email, age } = person;
return (
<div key={id} className='item'>
<h4>{firstName}</h4>
<p>{email}</p>
<p>{age}</p>
</div>
);
})}
</article>
</>
);
};
That is because FormControl is defined inside the ControlledInputs component. So, on each rerender of the ControlledInputs, you create a new FormControl function and that means that React will treat it as a different component than the one in the previous render, and so it will lose focus, as the old one is considered unmounted.
Just define the FormControl outside the other one, and pass it what extra data you need as props, and you should be set.

After editing data, redux cannot read id

i have a problem.
I use a form to edit my data, then when i want to see edited data, i get an ×
TypeError: Cannot read properties of undefined (reading 'id')
Pointing at my
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
Which is used to display data.
After refreshing the site (F5) it works, so i assume that the redux has problem with reading edited data for the first time, altough it do work with adding new data. anyone know what i can do?
My UserEditForm:
const UserEditForm = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.user);
const [state, setState] = useState({
name: "",
birthday: "",
img: "",
});
const [error, setError] = useState("");
console.log(id);
let history = useHistory();
let dispatch = useDispatch();
const { name, birthday, img } = state;
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
useEffect(() => {
if (user) {
setState({ ...user });
}
}, [user]);
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
const handleSubmit = (e) => {
dispatch(updateUser(state, id));
history.push("/");
setError("");
};
return (
<div>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
color="secondary"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit User</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Name"
value={name || ""}
name="name"
type="text"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="birthday"
name="birthday"
value={birthday || ""}
type="birthday"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="img"
value={img || ""}
name="img"
type="number"
onChange={handleInputChange}
/>
<Button
style={{ width: "100px" }}
variant="contained"
color="primary"
type="submit"
onChange={handleInputChange}
>
Update
</Button>
</form>
</div>
);
};
export default UserEditForm;
My UserList component:
const UserList = ({ users, history }) => {
const dispatch = useDispatch();
const fetchUsers = async () => {
const response = await axios
.get("http://localhost:3000/characters")
.catch((err) => {
console.log("Err: ", err);
});
dispatch(setUsers(response.data));
};
useEffect(() => {
fetchUsers();
}, []);
console.log(users);
return (
<div>
<button onClick={() => history.goBack()}>...back</button>
<li>
<Link to="/user/add">Add Users</Link>
</li>
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
</div>
);
};
const mapStateToProps = (state) => {
return {
users: state.allUsers.users,
};
};
export default connect(mapStateToProps, null)(UserList);

React - how to use map to pass an array of options on input of type unform select

I have a select input where I want to pass an options array object using map but when rendering my page only one option even when the array I'm using in the map has several items it insists on presenting only one
below all the code:
export default function PesquisarAulas() {
const dispatch = useDispatch();
const user = useSelector((state) => state.user.profile);
const [docente, setDocente] = useState([]);
const [docenteDisciplinas, setDocenteDisciplinas] = useState([]);
const [disciplinas, setDisciplinas] = useState([]);
const updateDisciplinas = [...disciplinas];
async function carregarDocente() {
const response = await api.get(`docente/findByUser/${user.id}`);
return response.data;
}
async function carregarDisciplinasDocente() {
const response = await api.get(`docente/${docente.id}/disciplinas`);
return response.data;
}
async function carregarDisciplina(disc) {
const response = await api.get(`disciplinas/${disc.id_disciplina}`);
return response.data;
}
useEffect(() => {
carregarDocente().then((value) => {
setDocente(value);
});
}, [user]);
useEffect(() => {
carregarDisciplinasDocente().then((value) => {
setDocenteDisciplinas(value);
});
}, [docente]);
useEffect(() => {
docenteDisciplinas.map((docDisc) =>
carregarDisciplina(docDisc).then((value) => {
updateDisciplinas.push(value);
setDisciplinas(updateDisciplinas);
})
);
}, [docenteDisciplinas]);
console.log(disciplinas);
function handleSubmit() {}
return (
<Container>
<div className="title">Pesquisar aulas</div>
<Form onSubmit={handleSubmit}>
<div className="input-box">
<span>Ano Letivo:</span>
<Input
name="anoLetivo1"
type="text"
placeholder="Introduza o ano letivo"
/>
</div>
<div className="input-box">
<span>Disciplinas:</span>
<Select
name="tech"
options={disciplinas.map((disciplina) => ({
id: disciplina.id,
title: disciplina.nome,
}))}
placeholder="Nenhum selecionado"
/>
</div>
<div className="input-box">
<span>Aulas de:</span>
<Input name="dataInicio1" type="datetime-local" id="pickup_time" />
<span style={{ marginLeft: '10px' }}>ate:</span>
<Input name="dataFinal1" type="datetime-local" id="pickup_time" />
</div>
<div className="input-box">
<span>Curso:</span>
<Input name="curso1" type="text" placeholder="Introduza o curso" />
</div>
<div className="input-box">
<span>Unidade Curricular:</span>
<Input
name="unidadeCurricular1"
type="text"
placeholder="Introduza a unidade curricular"
/>
</div>
<hr />
<button type="submit">Pesquisar</button>
</Form>
</Container>
);
}
the focus of the problem is on these two code snippets here:
const [disciplinas, setDisciplinas] = useState([]);
const updateDisciplinas = [...disciplinas];
useEffect(() => {
docenteDisciplinas.map((docDisc) =>
carregarDisciplina(docDisc).then((value) => {
updateDisciplinas.push(value);
setDisciplinas(updateDisciplinas);
})
);
}, [docenteDisciplinas]);
<Select
name="tech"
options={disciplinas.map((disciplina) => ({
id: disciplina.id,
title: disciplina.nome,
}))}
placeholder="Nenhum selecionado"
/>
I think the problem is that when the select is rendered only one item is inserted in the disciplines array,
I think maybe if there was a way to make Select wait until all the items in the disciplines array are ready so it can render, the problem would be solved.
Try using the select like this:
<select placeholder="Nenhum selecionado" >
{{disciplinas.map((disciplina) => {
<option value={disciplina.nome}>
{disciplina.nome}
</option>
})}}
</select>

How to validate email and password using react hooks?

I am getting state values while clicking submit button but I am unable to do the validation for my login form and how to display the error messages below the input field when I enter my input wrong or empty. please give me a solution to this.Thanks in advance.
const Login = () => {
const [state, setState] = useState({
email: "",
password: ""
});
const handleChange = (e) => {
const {id, value} = e.target
setState(prevState => ({
...prevState,
[id]: value
}))
}
const handleSubmitClick = (e) => {
e.preventDefault();
console.log("Authenticated",state);
}
return(
<>
<div className="container">
<div className="title">
<form onSubmit={handleSubmitClick}>
<div className="form-group">
<input
type="email"
className="email"
placeholder="Email"
value={state.email}
onChange={handleChange}/>
</div>
<div className="form-group">
<input
type="password"
className="password"
placeholder="Password"
value={state.password}
onChange={handleChange}/>
</div>
<button type="submit" className="button">Enter</button>
</form>
</div>
</div>
</>
)
}
export default Login;
If you want to perform client-side validation, you can create hook like this:
const useEmailValidation = (email) => {
const isEmailValid = /#/.test(email); // use any validator you want
return isEmailValid;
};
And then you can use this hook in your form component:
...
const isEmailValid = useEmailValidation(state.email);
const isPasswordValid = usePasswordValidation(state.password);
const isFormValid = isEmailValid && isPasswordValid;
return (
...
<input
className={classNames({ 'invalid': !isEmailValid })}
type="email"
value={state.email}
onChange={handleChange}
/>
{!isEmailValid && 'Some error message'}
<button type="submit" disabled={!isFormValid} className="button">Enter</button>
...
);
...
Your validator hook can return validation message instead of boolean, like:
const useEmailValidation = (email) => {
if (!email || email.length === 0) {
return 'Email cannot be empty';
}
const isEmailValid = /#/.test(email); // use any validator you want
if (!isEmailValid) {
return 'Invalid email provided';
}
return null;
};
Also it is a good practice to show validation message only after field was focused before and after user tried to submit the form.
Formik is a great plugin that will help you perform form validation. The examples are also quite clear.
Or you could do something like this:
const Login = () => {
const [error, setError] = useState(null);
const [state, setState] = useState({
email: '',
password: '',
});
const validateEmail = (email) => {
const re =
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
};
const handleChange = (e) => {
const { id, value } = e.target;
setState((prevState) => ({
...prevState,
[id]: value,
}));
};
const handleSubmitClick = (e) => {
e.preventDefault();
if (!validateEmail(state.email)) {
setError('Invalid Email');
}
if (state.password.length < 8) {
setError('Password must be at least 8 chars long');
}
if (!error) {
// No errors.
}
};
return (
<>
<div className='container'>
<div className='title'>
{error && <div style={{ color: 'red' }}>{error}</div>}
<form onSubmit={handleSubmitClick}>
<div className='form-group'>
<input
type='email'
className='email'
placeholder='Email'
value={state.email}
onChange={handleChange}
/>
</div>
<div className='form-group'>
<input
type='password'
className='password'
placeholder='Password'
value={state.password}
onChange={handleChange}
/>
</div>
<button type='submit' className='button'>
Enter
</button>
</form>
</div>
</div>
</>
);
};
export default Login;
For an empty validation you can check it preventing the submit if the field is empty, like
const handleSubmitClick = (e) => {
e.preventDefault();
if(email.trim() === '' || password.trim() === ''){
//Add a h1 or section with the error message
}else{
console.log("Authenticated",state);
}
}
As long as the email field type is equal to email, which is your case, the browser should give an alert if the string is not an email. ("user#example.com")

Resources