React Hook using Controller for a custom Input - reactjs

I'm using react-hook-form to valid fields before submitting my form. However, I'm trying to change one input to be react-number-format, but it is not using the same input style and it's not working for the register error validation.
import React, { useState } from 'react';
import { Controller, useForm } from "react-hook-form";
import {
Form,
Label,
Input,
Button
} from 'reactstrap';
import { FormGroup } from '#material-ui/core';
import moment from 'moment';
import DatePicker from "reactstrap-date-picker";
import NumberFormat from 'react-number-format';
const setErrorStyle = (name) => {
return {
borderColor: name ? 'red' : '',
boxShadow: name ? '0 0 1.5px 1px red' : ''
}
}
const Test = () => {
const [ addBill, setAddBill ] = useState({
debitAmt: '',
invoiceNumber: '',
memo: '',
invoiceDate: moment().format('YYYY-MM-DD'),
});
const { register, handleSubmit, errors, control } = useForm();
const submitAddBill = (data) => {
console.log(data);
}
return (
<>
<Form onSubmit={handleSubmit(submitAddBill)}>
<div className="row">
<div className="col-sm-2">
<FormGroup className="mr-10 mb-10">
<Label for="debitAmt" className="mr-sm-10">Debit Amt</Label>
<Controller
as={
<NumberFormat
thousandSeparator={true}
prefix={"$"}
onValueChange={(v) => {
setAddBill({...addBill, debitAmt: v.floatValue === undefined ? '' : v.floatValue})
}}
/>
}
name="debitAmt"
id="debitAmt"
variant="outlined"
defaultValue={addBill.debitAmt}
innerRef={register({ required: true })} aria-invalid={errors.debitAmt ? "true" : "false"}
control={control}
style={setErrorStyle(errors.debitAmt)}
/>
{errors.debitAmt && (
<span style={{ color: "red" }} role="alert">required</span>
)}
</FormGroup>
</div>
<div className="col-sm-2">
<FormGroup className="mr-10 mb-10">
<Label for="invoiceDate" className="mr-sm-10">Invoice Date</Label>
<DatePicker name="invoiceDate" id="invoiceDate"
value={addBill.invoiceDate} onChange={(e) => setAddBill({...addBill, invoiceDate: e ? moment(e).format('YYYY-MM-DD') : ''})}
innerRef={register({ required: true })} aria-invalid={errors.invoiceDate ? "true" : "false"}
style={setErrorStyle(errors.invoiceDate)}
/>
{errors.invoiceDate && (
<span style={{ color: "red" }} role="alert">required</span>
)}
</FormGroup>
</div>
<div className="col-sm-3">
<FormGroup className="mr-10 mb-10">
<Label for="invoiceNumber" className="mr-sm-10">Invoice Number</Label>
<Input type="text" name="invoiceNumber" id="invoiceNumber" placeholder="1234567"
innerRef={register({ required: true })} aria-invalid={errors.invoiceNumber ? "true" : "false"}
value={addBill.invoiceNumber} onChange={(e) => setAddBill({...addBill, invoiceNumber: e.target.value})}
style={setErrorStyle(errors.invoiceNumber)}
/>
{errors.invoiceNumber && (
<span style={{ color: "red" }} role="alert">required</span>
)}
</FormGroup>
</div>
<div className="col-sm-3">
<FormGroup className="mr-10 mb-10">
<Label for="memo" className="mr-sm-10">Memo</Label>
<Input type="text" name="memo" id="memo" placeholder="Memo"
innerRef={register()} aria-invalid={errors.memo ? "true" : "false"}
value={addBill.memo} onChange={(e) => setAddBill({...addBill, memo: e.target.value})}
style={setErrorStyle(errors.memo)}
/>
</FormGroup>
</div>
</div>
<Button type="submit" color="primary" size="sm" className="w-auto">Add Bill</Button>
</Form>
</>
)
}
export default Test;
Also, when I submit the form and check the log, the debitAmt data is not there.
Thanks

The prop innerRef doesn't exist on NumberFormat component instead use getInputRef prop on NumberFormat
Example Implementation
<FormGroup className="mr-10 mb-10">
<Label for="debitAmt" className="mr-sm-10">
Debit Amt
</Label>
<Controller
as={
<NumberFormat
thousandSeparator={true}
prefix={"$"}
onValueChange={(v) => {
setAddBill({
...addBill,
debitAmt: v.floatValue === undefined ? "" : v.floatValue
});
}}
/>
}
name="debitAmt"
id="debitAmt"
variant="outlined"
defaultValue={addBill.debitAmt}
getInputRef={register({ required: true })}
aria-invalid={errors.debitAmt ? "true" : "false"}
control={control}
style={setErrorStyle(errors.debitAmt)}
/>
{errors.debitAmt && (
<span style={{ color: "red" }} role="alert">
required
</span>
)}
</FormGroup>
Example Sandbox here

Related

How prevent submit edit form when anything is not changed?

I have a form like this that I created with context crud project. Here I want that if no changes have been made in the form, it should not be updated and a notification should be issued. How can I do this?
Note: also, if any input is empty, do not submit. How can I do this without required the input. How can I fix these problems?
import React from "react";
import { NavLink } from "react-router-dom";
import { useContext, useState, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { GlobalContext } from "../../context/GlobalState";
import styles from "../ContactForm/Form.module.scss";
import { toast } from "react-toastify";
const EditContactForm = () => {
const { contacts, UPDATE_CONTACT } = useContext(GlobalContext);
const [selectedContact, setSelectedContact] = useState({
id: "",
name: "",
surname: "",
fatherName: "",
specialty: "",
email: "",
gender: "",
test:''
});
const history = useNavigate();
const { id } = useParams();
useEffect(() => {
const userId = id;
const selectedContact = contacts.find((user) => String(user.id) === userId);
if (selectedContact) {
setSelectedContact(selectedContact);
}
}, [id, contacts]);
function onSubmit(e) {
e.preventDefault();
if(selectedContact){
UPDATE_CONTACT(selectedContact);
console.log("new user edited:", selectedContact);
history("/contacts");
toast('updated')
}
else if(selectedContact===contacts){
toast('anything doesnt changed') // problem is there
}
}
const handleOnChange = (e) => {
setSelectedContact((selectedContact) => ({
...selectedContact,
[e.target.name]: e.target.value,
}));
};
const inputHandleChange = (e) => {
setSelectedContact({
...selectedContact,
[e.target.name]: e.target.checked ? e.target.id : "",
});
};
const selectOptions = [
{ label: "One", value: 1 },
{ label: "Two", value: 2 },
{ label: "Three", value: 3 },
];
const onChange = (e) => setSelectedContact({ ...selectedContact, [e.target.name]: e.target.value })
return (
<div className={styles.form}>
<form onSubmit={onSubmit}>
<div class="mb-3 row row d-flex justify-content-around">
<label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Name</label>
<div class="col-sm-8">
<input
class="form-control"
name="name"
required
value={selectedContact?.name ?? ""}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row row d-flex justify-content-around">
<label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Surname</label>
<div class="col-sm-8">
<input
class="form-control"
name="surname"
required
value={selectedContact?.surname ?? ""}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row row d-flex justify-content-around">
<label className={`col-sm-2 p-0 ${styles.inputLabel}`}>
Father Name
</label>
<div class="col-sm-8">
<input
class="form-control"
name="fatherName"
required
value={selectedContact?.fatherName ?? ""}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row row d-flex justify-content-around">
<label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Email</label>
<div class="col-sm-8">
<input
class="form-control"
name="email"
required
value={selectedContact?.email ?? ""}
onChange={handleOnChange}
/>
</div>
</div>
<div class="mb-3 row row d-flex justify-content-around">
<label className={`col-sm-2 p-0 ${styles.inputLabel}`}>
Specialty
</label>
<div class="col-sm-8">
<input
class="form-control"
name="specialty"
required
value={selectedContact?.specialty ?? ""}
onChange={handleOnChange}
/>
</div>
</div>
<div className="mb-3 row row d-flex justify-content-around">
<label className={`col-sm-2 p-0 ${styles.inputLabel}`}>position</label>
<div className="col-sm-8 d-flex justify-content-center align-items-center">
<select
onChange={onChange}
value={selectedContact.test}
name="test"
class="form-select"
aria-label="Default select example"
>
{selectOptions.map((item) => (
<option
key={item.value}
value={item.value}
>
{item.label}
</option>
))}
</select>
</div>
</div>
<div className="mb-3 row row d-flex justify-content-around">
<label className={`col-sm-2 p-0 ${styles.inputLabel}`}>Gender</label>
<div className="col-sm-8">
<div class="form-check form-check-inline ">
<input
class="form-check-input"
type="radio"
name="gender"
id="male"
checked={selectedContact.gender === "male"}
onChange={inputHandleChange}
/>
<label class="form-check-label">Male</label>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="gender"
id="female"
checked={selectedContact.gender === "female"}
onChange={inputHandleChange}
/>
<label class="form-check-label">Female</label>
</div>
</div>
</div>
<div className="mb-3 row d-flex justify-content-around">
<div class="form-check col-sm-11">
<input
class="form-check-input"
type="checkbox"
name="updatesNotification"
id="update"
checked={selectedContact.updatesNotification === "update"}
onChange={(e) =>
setSelectedContact({
...selectedContact,
[e.target.name]: e.target.checked ? e.target.id : "",
})
}
/>
<label class="form-check-label" for="flexCheckDefault">
I want to be notified of updates
</label>
</div>
</div>
<div className={styles.buttons}>
<button type="submit" class="btn btn-primary">
Update a contact
</button>
<NavLink to="/contacts" className="btn btn-danger m-2">
Cancel
</NavLink>
</div>
</form>
</div>
);
};
export default EditContactForm;
import React, { useState } from "react";
import { useContext } from "react";
import { GlobalContext } from "../../context/GlobalState";
import { useNavigate } from "react-router-dom";
import { NavLink } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import styles from "../ContactForm/Form.module.scss";
import { toast } from "react-toastify";
import { Checkbox, Button, Form, Input, Select, Radio } from "antd";
const Form1 = () => {
const { ADD_CONTACT } = useContext(GlobalContext);
const [contact, setContact] = useState({
id: uuidv4(),
name: "",
surname: "",
fatherName: "",
specialty: "",
email: "",
gender: "",
updatesNotification: "",
test: "",
});
const { Option } = Select;
const { name, surname, fatherName, specialty, email } = contact;
let history = useNavigate();
const onSubmit = () => {
if (contact) {
ADD_CONTACT(contact);
history("/contacts");
console.log(contact);
toast.success("Contact successfully added");
}
else{
???
}
};
const selectOptions = [
{ label: "One", value: 1 },
{ label: "Two", value: 2 },
{ label: "Three", value: 3 },
];
return (
<>
<Form
onFinish={onSubmit}
className={styles.form}
name="myForm"
initialValues={{
remember: true,
}}
autoComplete="off"
labelCol={{
span: 2,
}}
wrapperCol={{
span: 16,
}}
>
<div className="row">
<Form.Item
label="Name"
rules={[{ required: true, message: "Please input your name!" }]}
>
<Input
placeholder="Enter Your Name"
value={name}
name="name"
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</Form.Item>
</div>
<Form.Item
label="Surname"
rules={[{ required: true, message: "Please input your surname!" }]}
>
<Input
placeholder="Enter Your Surname"
value={surname}
name="surname"
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</Form.Item>
<Form.Item
label="Father Name"
rules={[{ required: true, message: "Please input your surname!" }]}
>
<Input
placeholder="Enter Your FatherName"
value={fatherName}
name="fatherName"
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</Form.Item>
<Form.Item
label="Email"
rules={[{ required: true, message: "Please input your mail!" }]}
>
<Input
name="email"
placeholder="your mail"
value={email}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</Form.Item>
<Form.Item
label="Specialty"
rules={[{ required: true, message: "Please input your specialty!" }]}
>
<Input
name="specialty"
placeholder="your specialt"
value={specialty}
onChange={(e) =>
setContact({ ...contact, [e.target.name]: e.target.value })
}
/>
</Form.Item>
<Form.Item label='Category'>
<Select
onChange={(e)=>setContact({ ...contact, test : e })}
defaultValue='category'
// value={contact.test}
name="test"
style={{
width: 120,
}}
>
{selectOptions.map((item) => (
<Option key={item.value} value={item.value}></Option>
))}
</Select>
</Form.Item>
<Form.Item label="Gender">
<Radio.Group
onChange={(e) =>
setContact({
...contact,
[e.target.name]: e.target.checked ? e.target.id : "",
})
}
name="gender"
rules={[{ required: true, message: "Please your gender!" }]}
>
<Radio
id="female"
value="Female"
checked={contact.gender === "female"}
>
Female
</Radio>
<Radio id="male" value="Male" checked={contact.gender === "male"}>
Male
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item>
<Checkbox
name="updatesNotification"
checked={contact.updatesNotification === "update"}
id="update"
onChange={(e) =>
setContact({
...contact,
[e.target.name]: e.target.checked ? e.target.id : "",
})
}
>
I want to be notified of updates
</Checkbox>
</Form.Item>
<div className={styles.buttons}>
<Button type="primary" htmlType="submit">
Add contact
</Button>
<NavLink to="/contacts">
<Button danger>Cancel</Button>
</NavLink>
</div>
</Form>
</>
);
};
export default Form1;
enter image description here
One way to check if two objects are equal is to transform them into string.
JSON.stringify(selectedContact) === JSON.stringify(contacts.find((user) => user.id === selectedContact.id))
For checking if one if the data is empty one way is using the method some, this method send true if one the item in an array match the condition.
if (Object.keys(selectedContact).some(key => !selectedContact[key])) {
alert('There are missing information')
}

How do you get a nested value item in ant design

im quite new on reactJS and also ant design. right now im trying to get a value from a Form.List that i want to make it / render it as json nested data output.
my full code :
import { MinusCircleOutlined, PlusOutlined } from '#ant-design/icons';
import { Button, Form, Input, Space, DatePicker, Select } from 'antd';
import axios from 'axios'
import { useNavigate } from 'react-router-dom'
import Cookies from "js-cookies";
import moment from 'moment';
import 'moment/locale/zh-cn';
const Stockpickingnew = ({ title }) => {
const options = [
{
value: '1',
label: 'True',
},
{
value: '0',
label: 'False',
},
{
value: '7',
label: 'product_tmpl_id'
},
];
const Navigate = useNavigate()
const dateFormat = ['DD-MM-YYYY'];
//---------------------------------------------------------------------------------------------------------------
let headers = {
"Authorization": "Bearer " + Cookies.getItem('access_token')
}
const onFinish = (values) => {
console.log('Success:', values);
let stockpick = {
date: moment(values.date).format("DD-MM-YYYY"),
origin: values.origin,
picking_type_id: values.picking_type_id,
location_id: values.location_id,
location_dest_id: values.location_dest_id,
stock_move_ids: [{
demand: values.demand,
done: values.done,
product_uom: values.product_uom,
product_tmpl_id: values.product_tmpl_id,
}]
};
console.log(JSON.stringify(stockpick))
let params = JSON.stringify(stockpick)
axios.post('http://127.0.0.1:5000/api/stockpickings', params, { headers })
.then(() => {
Navigate('/')
})
.catch(error => {
if (error.response) {
console.log(error.response);
}
});
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
//---------------------------------------------------------------------------------------------------------------
return (
<>
<div className='new'>
<div className="top">
<h1>{title}</h1>
</div>
<div className="bottom">
<div className="stockPicking">
<Form
name="stockPickings"
layout="vertical"
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<div className="left">
<Form.Item
label="Origin :"
name='origin'
>
<Select
options={options}
placeholder="Origin"
/>
</Form.Item>
<Form.Item
label="Picking Type :"
name='picking_type_id'
>
<Select
options={options}
placeholder="Picking Type"
/>
</Form.Item>
<Form.Item
label="Date :"
name='date'
>
<DatePicker
format={dateFormat}
onChange={(dateInMomentFormat, dateInStringFormat) => {
console.log(dateInStringFormat);
}}
/>
</Form.Item>
</div>
<div className="right">
<Form.Item
label="Location :"
name='location_id'
>
<Select
options={options}
placeholder="Location"
/>
</Form.Item>
<Form.Item
label="Destination :"
name='location_dest_id'
>
<Select
options={options}
placeholder="Destination"
/>
</Form.Item>
</div>
<div className="stockMove">
<Form.Item>
<Form.List name="stock_move_ids">
{(fields, { add, remove }) => (
<>
{fields.map((field) => (
<Space
key={field.key}
style={{
display: 'flex',
marginBottom: 8,
}}
align="baseline"
>
<Form.Item
{...field}
name={[field.name, 'demand']}
key={[field.key, 'demand']}
rules={[
{
required: true,
message: 'Missing Demand',
},
]}
>
<Input placeholder="Demand" />
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'done']}
key={[field.key, 'done']}
>
<Select
options={options}
placeholder="Done"
/>
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'product_uom']}
key={[field.key, 'product_uom']}
rules={[
{
required: true,
message: 'Missing product_uom',
},
]}
>
<Select
options={options}
placeholder="product_uom"
/>
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'product_tmpl_id']}
key={[field.key, 'product_tmpl_id']}
rules={[
{
required: true,
message: 'Missing product_tmpl_id',
},
]}
>
<Select
options={options}
placeholder="product_tmpl_id"
/>
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Space>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form.Item>
</div>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</div>
</div>
</div>
</>
)
}
export default Stockpickingnew
im sorry if it's really hard to read but basically, what i really want to do is my Form.List can get a value as nested data like :
stock_move_ids: [{
demand: values.demand,
done: values.done,
product_uom: values.product_uom,
product_tmpl_id: values.product_tmpl_id,
}]
my console.log (values) and console.log JSON.stringify(stockpick) do have different result as image below.
first one is from console.log values and the bottom one is from console.log stockpick
Screenshoot here
stock_move_ids values have 0th index you can access it like this.
let stockpick = {
date: moment(values.date).format("DD-MM-YYYY"),
origin: values.origin,
picking_type_id: values.picking_type_id,
location_id: values.location_id,
location_dest_id: values.location_dest_id,
stock_move_ids: [
{
demand: values?.stock_move_ids?.[0]?.demand,
done: values?.stock_move_ids?.[0]?.done,
product_uom: values?.stock_move_ids?.[0]?.product_uom,
product_tmpl_id: values?.stock_move_ids?.[0]?.product_tmpl_id,
},
],
};

React Formik automatically giving me error whenever I write in a field

I have the following functional component:
import React from "react";
import { Card, Row, FormGroup,Label,Button } from 'reactstrap';
import { Formik, Form, Field } from 'formik';
import axios from "axios";
const addSlidersUrl = "anApiUrl";
const validateSliderSlug = (value) => {
let error;
if(!value){
error="Please enter a Slider Slug value";
}
return error;
}
const validateSliderImage = (value) => {
let error;
if(!value){
error="Please enter a Slider Image value";
}
return error;
}
const validateSliderEnText = (value) => {
let error;
if(!value){
error="Please enter a Slider En Text value";
}
return error;
}
const validateSliderArText = (value) => {
let error;
if(!value){
error="Please enter a Slider Ar Text value";
}
return error;
}
const validateSliderEnButtonText = (value) => {
let error;
if(!value){
error="Please enter a Slider En Button Text value";
}
return error;
}
const validateSliderArButtonText = (value) => {
let error;
if(!value){
error="Please enter a Slider Ar Button Text value";
}
return error;
}
const validateSliderEnButtonLink = (value) => {
let error;
if(!value){
error="Please enter a Slider En Button Link value";
}
return error;
}
const validateSliderArButtonLink = (value) => {
let error;
if(!value){
error="Please enter a Slider Ar Button Link value";
}
return error;
}
const AddSlider = (props) => {
const ontNewSliderSubmit = (values) => {
if( values.sliderSlug !== '' && values.sliderImage !== '' && values.sliderEnText !== '' && values.sliderArText !== '' && values.sliderEnButtonText !== '' && values.sliderArButtonText !== '' && values.sliderEnButtonLink !== '' && values.sliderArButtonLink !== ''){
axios.post(
addSlidersUrl,
{
adminid: props.adminid,
token: props.adminlogintoken,
slider_slug: values.sliderSlug,
slider_image: values.sliderImage,
slider_en_text: values.sliderEnText,
slider_ar_text: values.sliderArText,
slider_en_button_text: values.sliderEnButtonText,
slider_ar_button_text: values.sliderArButtonText,
slider_en_button_link: values.sliderEnButtonLink,
slider_ar_button_link: values.sliderArButtonlink,
}
)
.then(
res => console.log(res)
)
.catch(
err => console.log(err)
);
}
}
return (
<Row>
<Card>
<div style={{ width: "90%", marginLeft: "auto", marginRight: "auto" }}>
<Row style={{ textAlign: "center" }}>
Add A New Slider
</Row>
<Row>
<Formik onSubmit={ontNewSliderSubmit}>
{({ errors}) => (
<Form>
<FormGroup className="form-group has-float-label">
<Label for="sliderSlug">
Slider Slug:
</Label>
<Field
className="form-control"
name="sliderSlug"
validate={validateSliderSlug}
/>
{errors.sliderSlug && (
<div className="invalid-feedback d-block">
{errors.sliderSlug}
</div>
)}
</FormGroup>
<FormGroup className="form-group has-float-label">
<Label for="sliderImage">
Slider Image:
</Label>
<Field
className="form-control"
name="sliderImage"
validate={validateSliderImage}
/>
{errors.sliderImage && (
<div className="invalid-feedback d-block">
{errors.sliderImage}
</div>
)}
</FormGroup>
<FormGroup className="form-group has-float-label">
<Label for="sliderEnText">
Slider En Text:
</Label>
<Field
className="form-control"
name="sliderEnText"
validate={validateSliderEnText}
/>
{errors.sliderEnText && (
<div className="invalid-feedback d-block">
{errors.sliderEnText}
</div>
)}
</FormGroup>
<FormGroup className="form-group has-float-label">
<Label for="sliderArText">
Slider Ar Text:
</Label>
<Field
className="form-control"
name="sliderArText"
validate={validateSliderArText}
/>
{errors.sliderArText && (
<div className="invalid-feedback d-block">
{errors.sliderArText}
</div>
)}
</FormGroup>
<FormGroup className="form-group has-float-label">
<Label for="sliderEnButtonText">
Slider En Button Text:
</Label>
<Field
className="form-control"
name="sliderEnButtonText"
validate={validateSliderEnButtonText}
/>
{errors.sliderEnText && (
<div className="invalid-feedback d-block">
{errors.sliderEnButtonText}
</div>
)}
</FormGroup>
<FormGroup className="form-group has-float-label">
<Label for="sliderArButtonText">
Slider Ar Button Text:
</Label>
<Field
className="form-control"
name="sliderArButtonText"
validate={validateSliderArButtonText}
/>
{errors.sliderArButtonText && (
<div className="invalid-feedback d-block">
{errors.sliderArButtonText}
</div>
)}
</FormGroup>
<FormGroup className="form-group has-float-label">
<Label for="sliderEnButtonlink">
Slider En Button Link:
</Label>
<Field
className="form-control"
name="sliderEnButtonLink"
validate={validateSliderEnButtonLink}
/>
{errors.sliderEnButtonLink && (
<div className="invalid-feedback d-block">
{errors.sliderEnButtonLink}
</div>
)}
</FormGroup>
<FormGroup className="form-group has-float-label">
<Label for="sliderArButtonLink">
Slider Ar Button Link:
</Label>
<Field
className="form-control"
name="sliderArButtonLink"
validate={validateSliderArButtonLink}
/>
{errors.sliderArButtonLink && (
<div className="invalid-feedback d-block">
{errors.sliderArButtonLink}
</div>
)}
</FormGroup>
<div style={ {display:"flex",flexDirection:"row",alignItems:"center",width:"50%",justifyContent:"space-between"} }>
<Button
color="success"
type="submit"
>
Add Slider
</Button>
<Button
color="danger"
type="button"
onClick={props.cancelAddingItem}
>
Cancel
</Button>
</div>
</Form>
)}
</Formik>
</Row>
</div>
</Card>
</Row>
);
}
export default AddSlider;
It's just a simple component that has a formik which should allow me to fill in the fields and when pressing the Add Slider button it should validate that I didn't leave any field empty before executing a function. The problem is that as soon as I type in any field I receive the following 2 errors and I cannot understand why:
first error
second error
Edit: Note that I'm getting the error as soon as I type 1 letter in any of the fields not after i press the submit button.
SliderEnText is undefined - you checking for empty string right now:
values.sliderArButtonText !== ''
try for undefined:
Checking for Undefined In React

React Formik: My custom onBlur override default touched behavior and not displaying my ErrorMessage

I just started learning to code 2 months ago, this week I tried to work with Formik and had this issue where I can't display my ErrorMessage after I added onBlur on the field, before added it, was working normally.
Also, I didn't find another way to work with onBlur, that's why I code it on the field.
I appreciate it if have a hand.
import { Formik, Field, Form, ErrorMessage } from "formik";
import Schema from "./Schema";
import { Container, Row, Col } from "react-bootstrap";
import { useState } from "react";
import Result from "./Result";
import { BsEyeSlashFill } from "react-icons/bs";
const Register = () => {
const [data, setData] = useState(false);
const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setConfirmShowPassword] = useState(false)
const [checkMarkName, setCheckMarkName] = useState(null)
const [checkMarkSurname, setCheckMarkSurname] = useState(false)
const [checkMarkEmail, setCheckMarkEmail] = useState(false)
const [checkMarkPass, setCheckMarkPass] = useState(false)
const [checkMarkConfirmPass, setCheckMarkConfirmPass] = useState(false)
const hidePassword = () => {
setShowPassword(!showPassword)
}
const hideConfirmPassword = () => {
setConfirmShowPassword(!showConfirmPassword)
}
function onSubmit(values, actions) {
setData(values)
}
return (
<Formik
validationSchema={Schema}
onSubmit={onSubmit}
validateOnMount
initialValues={{
name: "",
surname: "",
email: "",
password: "",
confirmPassword: "",
}}
>
{(props) => (
<Container>
<Row className="justify-content-center mt-3" >
<Col className="text-center d-flex justify-content-center" md={8}>
<Form className="mt-5 div-form w-100">
{console.log(props)}
<div className="errors mt-3">
<label>Nome</label>
<Field onBlur={() => {
if(!props.errors.name)(
setCheckMarkName(true)
)
}} name="name" className={checkMarkName ? "form-control form-control-green" : "form-control"} type="text" />
<div><ErrorMessage name="name" /></div>
</div>
<div className="errors mt-3">
<label>Surname</label>
<Field onBlur={() => {
if(!props.errors.surname)(
setCheckMarkSurname(true)
)
}} name="surname" className={checkMarkSurname ? "form-control form-control-green" : "form-control"} type="text" />
<div><ErrorMessage name="surname" /></div>
</div>
<div className="errors mt-3">
<label>Email</label>
<Field onBlur={() => {
if(!props.errors.email)(
setCheckMarkEmail(true)
)
}} name="email" className={checkMarkEmail ? "form-control form-control-green" : "form-control"} type="email" />
<div><ErrorMessage name="email" /></div>
</div>
<div className="errors mt-3 position-relative">
<label>Password</label>
<Field onBlur={() => {
if(!props.errors.password)(
setCheckMarkPass(true)
)
}}
name="password"
className={checkMarkPass ? "form-control form-control-green" : "form-control"}
type={showPassword ? 'text' : 'password'}
></Field>
<span className="position-relative eyes text-white"><BsEyeSlashFill onClick={() => hidePassword()} /></span>
<div className="position-relative error-msg"><ErrorMessage name="password" /></div>
</div>
<div className="errors mb-4 position-relative">
<label>Confirm Password</label>
<Field onBlur={() => {
if(!props.errors.confirmPassword)(
setCheckMarkConfirmPass(true)
)
}}
name="confirmPassword"
className={checkMarkConfirmPass ? "form-control form-control-green" : "form-control"}
type={showConfirmPassword ? 'text' : 'password'}
/>
<span className="position-relative eyesConfirm text-white"><BsEyeSlashFill onClick={() => hideConfirmPassword()} /></span>
<div className="position-relative error-msg"><ErrorMessage name="confirmPassword" /></div>
</div>
<button
className="btn btn-primary mb-3"
disabled={!props.isValid}
type="submit"
>
Enviar
</button>
<button
className="btn btn-primary mb-3 ml-3"
type="button"
onClick={() => setData(false)}
>
Reset
</button>
</Form>
</Col>
{
data &&
<Result data={data}/>
}
</Row>
</Container>
)}
</Formik>
);
};
export default Register;

React, Display message after submitting form with react-hook-form

I use react-hook-form and would like to display message to the user after submitting form. I know how to do that with alert, but would like to have that message as a paragraph. After submitting fields should be again empty.
Here is my Form component:
import React from "react";
import { useForm } from "react-hook-form";
const Form = ({ title }) => {
const { register, handleSubmit, errors } = useForm();
const onSubmit = (data, e) => {
e.preventDefault();
console.log(data);
alert(`thank you ${data.name} for your message`);
};
return (
<div className="formContainer">
<Title title="Lets stay in touch" />
<div className="form">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form__row">
<input
className={`inputForm ${errors.name ? "inputFormError" : ""}`}
name="name"
type="text"
placeholder="name"
ref={register({ required: true })}
/>
<input
className={`inputForm ${
errors.surname ? "inputFormError" : ""
}`}
name="surname"
type="text"
placeholder="surname"
ref={register({ required: true })}
/>
</div>
<div>
<textarea
className={`inputForm areaForm ${
errors.message ? "inputFormError" : ""
}`}
name="message"
placeholder="Your message"
ref={register({ required: true })}
></textarea>
</div>
<div>
<button className="form__formButton" type="submit">
Send
</button>
</div>
</form>
</div>
</div>
);
};
export default Form;
Pretty simple with just a useState to show the message and reset API from hookForm to reset the form :
import React from "react";
import { useForm } from "react-hook-form";
const Form = ({ title }) => {
const [message, setMessage] = useState('');
const { register, handleSubmit, errors, reset } = useForm();
const onSubmit = (data, e) => {
e.preventDefault();
console.log(data);
setMessage(`thank you ${data.name} for your message`);
reset();
};
return (
<div className="formContainer">
<Title title="Lets stay in touch" />
<div className="form">
{message}
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form__row">
<input
className={`inputForm ${errors.name ? "inputFormError" : ""}`}
name="name"
type="text"
placeholder="name"
ref={register({ required: true })}
/>
<input
className={`inputForm ${
errors.surname ? "inputFormError" : ""
}`}
name="surname"
type="text"
placeholder="surname"
ref={register({ required: true })}
/>
</div>
<div>
<textarea
className={`inputForm areaForm ${
errors.message ? "inputFormError" : ""
}`}
name="message"
placeholder="Your message"
ref={register({ required: true })}
></textarea>
</div>
<div>
<button className="form__formButton" type="submit">
Send
</button>
</div>
</form>
</div>
</div>
);
};
export default Form;

Resources