Validation for Input form component React - reactjs

I have a form component that include multiple TextFields and each one have different validation and error. Assume my TextField had custom validation prop that will take some conditions and show validation either onChange or onBlur for each TextField. I also have custom error prop that display message without condition.
const Address = ({
onChange,
required,
error,
value = {},
validation = undefined,
}: AddressProps) => {
const validator = {
validationAddress: (value: string) => (value.length === 0) ? 'Address is required' : '',
validationCity: (value: string) => (value.length === 0) ? 'City is required' : '',
}
const handleChange = (event) => {
...
}
return (
<React.Fragment>
<TextField
id="address"
label="address"
type="text"
required={required}
onChange={handleChange}
value={value.address}
validationEvent="change"
validation={validator.validationAddress}
/>
<TextField
id="city"
label="city"
type="text"
required={required}
onChange={handleChange}
value={value.city}
validationEvent="change"
validation={validator.validationCity}
/>
</React.Fragment>
export default Address;
After that I will implement my Address component in an App with submit button.
const App = () => {
const handleSubmit = () => {
...
}
return (
<Address />
<button type='submit' onClick={handleSubmit}>
Submit
</button>
)
}
export default App;
I saw many examples that input and form put together with submit button but I am struggling with handle them separately this way. My task is need to handle validation in Address component but have submit button as an optional option outside the Address component. My goal is validation message should not show until Submit button is clicked.

Try this:
move validator to parent component
pass validatorMessage useState var to Address component
call the validator by the click of submit button
Now the message is managed in the parent component and you control when the submit button displays it.

I would suggest to consider a different approach: there is no need to manually implement validation, we can use the browser built-in validation feature:
https://medium.com/p/491327f985d0
Essentially I use standard HTML mark-up and properties.
Implementation example:
export default function App() {
const onSubmit = (data: FormData) => {
console.log(Object.fromEntries(data.entries()));
};
return (
<div className="App">
<Form onSubmit={onSubmit}>
<h2>A simple form</h2>
<TextInput label="Name:" id="name" name="name" required />
<TextInput
label="Email:"
id="email"
type="email"
name="email"
required
/>
<TextInput label="Address:" id="address" name="address" />
<TextInput
label="Tel:"
id="tel"
name="tel"
type="tel"
pattern="((\+44(\s\(0\)\s|\s0\s|\s)?)|0)7\d{3}(\s)?\d{6}" // don't rely on this
/>
<button>Submit</button>
</Form>
</div>
);
}
The Form component itself is very simple:
<form
action={action}
onSubmit={handleSubmit}
noValidate
className={style.form}
>
<div className={style.wrapper}>{children}</div>
</form>
It sets the noValidate attribute to prevent the default error notification to pop up.
The input boxes are wrapped in the form element.
The form element has an onSubmit event handler: it gets triggered when user clicks on the submit button OR when the user hit return using the keyboard.
At that point we use e.preventDefault(); to prevent default form submission and handle it manually.

Related

Antd TypeScript : Log data when user clicks enter

In the project I'm working, I have wrapped the input around a form, and the idea is when the user types something and clicks enter, the data is logged. But the issue is I'm not getting such logs.
Here is my code :
Index.tsx
const onFinish = (values: any) => {
console.log("yoyo");
console.log(values);
};
<Form name="control-ref" onMouseEnter={onFinish}>
<Form.Item name="note" rules={[{ required: true }]}>
<InputField
variant="search"
placeholder="Search"
addonAfter={selectAfter}
className="search-field"
/>
</Form.Item>
</Form>
The InputField with the specified variant returns this components
const SearchField: React.FC<IInputFieldProps> = (props) => {
const { placeholder } = props;
return (
<Input
className="search-field"
placeholder={placeholder || 'Search'}
{...props}
/>
);
};
Please help
Log the data when the form is submitted. Forms can be submitted by pressing enter.
<Form name="control-ref" onFinish={(values: any) => {
console.log("yoyo");
console.log(values);
}}>
{...}
</Form>
Edit: updated submission callback according to ant design react docs

React form not submitting when using button nested inside Link tag

In my app I have an order form with a button to "complete order" at the bottom. What I want the button to do is submit the form and push the user to the confirmation page where their order will be displayed. Right now I can do one or the other, but can't figure out how to to both.
My form component:
<form onSubmit={onSubmit}>
<label>Name:
<input
type="text"
name="name"
placeholder="Name"
value={values.name}
onChange={onChange}
/>
</label>
<Link to="/confirmation" >
<button>Complete Order</button>
</Link>
</form>
My onSubmit function:
const formSubmit = () => {
const newOrder = {
name: formValues.name.trim(),
}
setOrder(order.concat(newOrder));
setFormValues(initialFormValues);
}
I can tell my formSubmit function submit isn't working because my formValues don't reset after form submission. If I remove the Link tag and just have the button, they do, but then I don't get the redirect to the confirmation page. Any suggestions on what I can do?
If you want to update/reset the form state then navigate to the "/confirmation" path, you can't use a Link and a button/submit the form at the same time.
Remove the Link component and issue an imperative navigation after enqueueing the state updates. Don't forget to prevent the default form action from occurring so the app isn't reloaded.
import { useNavigate } from 'react-router-dom';
...
const navigate = useNavigate();
...
const onSubmit = (e) => {
e.preventDefault();
const newOrder = {
name: formValues.name.trim(),
};
setOrder(order.concat(newOrder));
setFormValues(initialFormValues);
navigate("/confirmation");
}
...
<form onSubmit={onSubmit}>
<label>Name:
<input
type="text"
name="name"
placeholder="Name"
value={values.name}
onChange={onChange}
/>
</label>
<button type="submit">Complete Order</button>
</form>

ReactJS: OnChange handler auto submitting data before onClick

I'm still relatively new to React/Javascript & working with its functions. I created a component that takes user input and renders a button that allows a user to link to an outside URL.
The button title is created by the user and then the URL is added.
However, when a url is pasted or I begin typing it, the onChange handler automatically creates the button without using the onSubmit function. So if I begin typing a paste a url (even if the data is wrong), the onChange event takes whatever I've input without allowing me to click "submit first".
I'm following this tutorial as a guideline for creating my onChange/onSubmit functions: https://www.youtube.com/watch?v=qH4pJISKeoI&t=304s. His demo does not have the same issue and his input fields solve a different problem.
onChange & onSubmit Functions
this.state = {
links: [],
url: '',
title: ''
}
}
onChange = (e) => {
e.preventDefault(e)
this.setState({
[e.target.name]: e.target.value
})
}
// onSubmit
onSubmit = e => {
e.preventDefault(e)
}
...
render() {
if (this.state.url === '') {
return (
<>
<form>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.setState({ title: e.target.value })}
/>
<input
name="url"
type="url"
placholder="your-link.com"
onClick={(e) => { e.stopPropagation() }}
disabled={this.state.title === ''}
onChange={e => this.setState({ url: e.target.value })}
/>
<br />
</form>
<button onClick={this.onSubmit}>Submit</button>
</>
)
} else {
return (
<>
<div>
<p>{this.state.title}</p>
</div >
</>
)
}
}
}
I've tried separating the onChange events using onChange={this.title} and {this.url} , disabling the URL field until the title is added, and adding onClick={(e) => { e.stopPropagation() }} in the url input field to prevent autosubmission as shown in the code above.
Any help understanding what causes this problem would be appreciated.
Let's check what is happening:
We have onChange on input with url.
When anything is being changed in this input field,
On change is called and it triggers render method.
In render if (this.state.url === '') { this is no longer true so it creates link without needing to submit.
Prevent default will not work while you have params in it:
e.preventDefault(e)
// probably this may be a typo instead?
// it's preventing you to go further line due to error.
Remove e param and it should be fine:
e.preventDefault()
<form onSubmit={this.onSubmit}>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.onChange(e)}
/>
<input
name="url"
type="url"
placholder="your-link.com"
disabled={this.state.title === ''}
onChange={e => this.onChange(e)}
/>
<br />
<button type="submit">Submit</button>
</form>
do changes like this and check

Redux Form Checkbox Validation

I have the following code. The checkbox is for confirming that the user has read Terms and Conditions. Im not sure how to add validation for this on the front end. i.e. If the user clicks submit without checking this box, I want to highlight this text in some way that lets the user know to agree to Terms.
<Field
label='Terms'
name="terms-and-conditions"
type="checkbox"
component={this.renderField}
submissionErrors={this.state.submissionErrors}
/>
You can create a custom component for the Field component. In the custom component you will receive error prop so you can process with additional styling, error messages, etc. If you want to validate on submit, pass onSubmit prop to the decorated component.
Live example: https://codesandbox.io/s/207mj8k3py
Create a custom component with the error logic:
const Checkbox = ({ input, meta: { touched, error } }) => (
<div style={{ border: touched && error ? "1px solid red" : "none" }}>
<input type="checkbox" {...input} />
<label>Terms and conditions</label>
</div>
)
Set Field's component prop to Checkbox:
const SimpleForm = ({ handleSubmit, onSubmit }) => (
<form onSubmit={handleSubmit(onSubmit)}>
<Field
name="termsAndConditions"
component={Checkbox}
/>
<div>
<button type="submit">Submit</button>
</div>
</form>
)
In onSubmit function, check if the checkbox is checked, if not - throw SubmissionError with the name of the Field:
const onSubmit = values => {
if (!values.termsAndConditions) {
throw new SubmissionError({
termsAndConditions: 'Field required'
})
}
console.log('Form submitted')
}
Decorate the form:
export default reduxForm({
form: "simple",
onSubmit
})(SimpleForm)

Submitting redux form values

I am new to react and redux technology. now started building an application that contains several redux forms. We want to submit simple form with values.
For ex: login form
Username : text input field
Password: text input field
Submit button
After entering values in fields and click on submit button i want to get the username and password field values in object or json data .. so that I can store it to my server with POST method.
Right now we are using handleSubmit(), but data is not coming as object
1 - The best practice to deal with input values are making them controlled. Which means :
Instead of
<input type='password' />
You do :
<input
type='password'
value={password}
onChange={ event => myInputHandler( event.target.value ) }
/>
The value might come from your state, redux state or as a props etc.
Your handler function differs according to where you store it.
I will give you an example with react state :
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
So whenever someone types, your onChange handler will be called, so that your react state will update with the input ( event.target.value ).
2 - If you need these values when a user submits, then you need to wrap these input fields within a form element and attach a onSubmit handler.
onSubmitHandler( event ){
event.preventDefault()
let password = this.state.password
// use password or other input fields, send to server etc.
}
<form onSubmit={ event => this.onSubmitHandler(event) }>
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
</form>
Hope you get what you need.
If you are using redux to store state then use redux-from then use redux from
import React from 'react'
import {Field, reduxForm} from 'redux-form'
const SimpleForm = props => {
const {handleSubmit, submitting} = props return (
<form onSubmit={handleSubmit(e=>console.log('your form detail here', e))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name" />
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field name="lastName" component="input" type="text" placeholder="Last Name" />
</div>
</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
</div>
</form>
) }
export default reduxForm({ form: 'simple'})(SimpleForm)
Go here for more detail
https://redux-form.com
I put the name of the input as the key that I want to use.
Then each time the input changes I destructure the event passed to the onChange function, and I use the name,value to update the state.
On form submit make sure to use preventDefault(); in order to avoid the page refreshing.
import React, { Component } from 'react'
class FormExample extends Component {
constructor(props){
super(props)
this.state = {
formData: {}
}
}
handleInputChange = ({ target: { name,value } }) => {
this.setState({
formData: {
...this.state.formData,
[name]: value
}
})
}
handleFormSubmit = e => {
e.preventDefault()
// This is your object
console.log(this.state.formData)
}
render() {
return(
<div>
<Form
handleSubmit={this.handleFormSubmit}
handleChange={this.handleInputChange}
/>
</div>
)
}
}
const Form = ({ handleSubmit, handleChange }) => (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} name="username" type="text" placeholder="Username" />
<input onChange={handleChange} name="password" type="password" placeholder="Password" />
<button>Submit</button>
</form>
)
export default FormExample

Resources