How do I tell if a Form is Valid / Invalid in React?
Angular has this syntax on Formbuilders.
this.form.valid;
I am using this coding syntax. Curious if anything exists in the React library?
Currently using Material UI Library.
Right now, I am doing if else statements and error checking all 10 fields. Looking for shorthand method.
https://onestepcode.com/creating-a-material-ui-form/
<form onSubmit={handleSubmit}>
<Grid container alignItems="center" justify="center" direction="column">
<Grid item>
<TextField
id="name-input"
name="name"
label="Name"
type="text"
value={formValues.name}
onChange={handleInputChange}
/>
</Grid>
<Grid item>
<TextField
id="age-input"
name="age"
label="Age"
type="number"
value={formValues.age}
onChange={handleInputChange}
/>
I'd recommend using a library called Formik. It takes a bit of time to learn, but it's a really powerful library, and I use it all the time now (with MUI).
As far as i understood your problem, you want to validate the form.
Which can be done by checking if the states are valid or not.
function handleSubmit(e){
e.preventDefault(); // to stop the form submission refresh the page
// now you can check the the validation part
// here are some sample validation that will check if the uername has 5
// characters or not and checks if the age is greater than 18 or not.
// validations
if(formValues.name.length < 5 ) return;
if(formValues.age < 18) return;
//if the code reaches this point then it is valid form
sendToDb();
//similar more functions or statements can be called
}
By checking the state value in the submission of the form it can be
validated.
The above mentioned way is the manual way but if you want to validate it using a single line validation by using some third party liberary, then this is the solution that i would likely go with.
I found this package in npmjs it works fine. This is how you can use it.
1. Install the package.
npm install react-native-input-validator
2. Usage:
import TextInput from "react-native-input-validator";
<TextInput type="email" ref={someReference}/>
// check the value is valid or not in the submission of the form by using
//[reference].isValid() method
someReference.isValid();
Hope it helps thank you.
for more reference check the package and see the use in more details in the examples.
package : https://www.npmjs.com/package/react-native-input-validator
To tell if a form content is valid or not - regardless the framework - you can simply use the following:
const handleSubmit = (e) => {
e.preventDefault();
const formElement = e.target;
const isValid = formElement.checkValidity();
// add more logic here
}
...
<form
action={action}
onSubmit={handleSubmit}
className={style.form}
>
<input type='email' name='email' />
<input type='number' name='age' required />
</form>
This will use the built-in validation function and will return true if the email is correct and the age is provided.
Please note that email is not 'required', i.e. an empty value is considered correct.
I just wrote an article where I discuss exactly this: form validation/submission using built-in validation API.
No need to install any package!
https://medium.com/p/491327f985d0
Related
I'm trying to render an <input> field with autofocus:
<input type="text" autoComplete="off" autoFocus={true} className="form-control" />
But it's being rendered as:
<input type="text" autocomplete="off" class="form-control">
And the input does not focus.
Why is that? How can I get the autofocus attribute to render?
This is expected, actually. React will manually call focus() on the relevant element, but it will not add the attribute itself.
Here is a quote from Dan Abramov from a ticket response from ~2 years ago:
This is intentional because it works very differently in different browsers. So instead of actually setting a DOM attribute, we polyfill its behavior in JavaScript.
Also, from another thread:
Chrome respects dynamically added elements with autoFocus if there hasn’t been one before. Even creating an input with autoFocus, adding it to the document, and removing it in the next tick is enough to disable autofocusing of any elements added in the future in Chrome.
Firefox just doesn’t care about any dynamically added elements with autoFocus at all.
And Safari always respects them.
That being said, you could still force the attribute with autofocus="true" instead of autoFocus={true} but it might not actually work in a reliable fashion. After all, there is a reason the React team polyfilled this.
In other words, if you want a reliable, consistent cross-browser behavior use autoFocus, if you must have the native attribute you can use autofocus="true", but know that you'll be at the mercy of letting the browser decide when and how said element will be focused.
You can try using a ref, and setting the focus when your component is ready.
const YourComponent = (props) => {
const inputEl = useRef(null);
useEffect(() => {
inputEl.current.focus();
}, []);
return <div>
<input autofocus="true" ref={inputEl} />
</div>;
}
Answer by Brandon works perfectly. Additionally, if you want to autofocus on an input on a Modal for example, just keep track of the modal state and use that to focus. For example:
const refModal = useRef(null);
useEffect(() => {
if(modalOpen) {
refModal.current.focus();
}
}, [modalOpen]);
I am writing a front-end app in Typescript and React and am using MUI. I have the following code for a form:
<TextField
label="Password"
value={this.state.password}
placeholder="Choose a password"
type="password"
onChange={(event: any) => this.setState({
password: event.target.value
})}
onBlur={console.log('here')}
error={this.state.passwordError}
/>
With this code, every time I click a key, onBlur gets fired. Isn't it only supposed to fire when I leave the form?
Would be helpful to see the onblur function. It doesn't look like you want to pass anything to it, so simply changing the line onBlur={this.onblur()} to onBlur={this.onblur} should do the trick.
However, if your function looks like this
onblur() {
...
}
then you should bind the context to it ('this'). Instead, I'd suggest going for
onblur = event => {
...
}
which will have the context already binded.
I am trying to use Formik on my form that successfully does some state lift up from a custom Input child component to its parent (following that tutorial from React's official website)
The following sandbox shows a basic example of what I have so far :
https://codesandbox.io/s/formik-with--or-without-custom-component-d8sof
(yes, there is some styled-components going on with InputStyled but it's supposed to be "transparent")
<Input //switch to input to try other scenario
type="number"
name="surface"
placeholder="please type surface"
onValueChange={handleSurfaceChange}
unit="sq feet"
value={values.surface}
onChange={handleChange}
/>
The excerpt above shows a custom component called Input (please note the capitalized "I")
With this custom component Input : lifting state up works but surface is not tracked by Formik and validation always fails.
With input (lower case - not calling my custom component) : validation by Formik works but I'm not using my custom component therefore I'm not engaging in the lifting of the child state up.
=> My goal would be to make both work.
So I tried using <Field component={Input} /> instead of my <Input />
https://jaredpalmer.com/formik/docs/api/field
But I cannot get my head around how to make the code work.
I started working on another codesanbox example following different trails here and there but things are getting messy.
https://codesandbox.io/s/formik-with--or-without-custom-component-ybbm7
In the parent:
<Field
component={Input} //my custom React Component
type="number"
name="surface"
placeholder="please type surface"
onValueChange={handleSurfaceChange}
value={values.surface}
//at a loss below
//onChange={handleChange}
// handleChange={e => {
// console.log("Entering handleChange in Field...");
// // call the built-in handleChange
// handleChange(e);
// // and do something about e
// let someValue = e.currentTarget.value;
// console.log("someValue = " + someValue);
// }}
/>
In the child (it's a styled-component, nothing fancy,just a regular input "decorated" with CSS) :
<InputStyled
{...field}
{...props}
id={props.name}
name={props.name}
type={props.type}
//value={props.value}
onChange={handleChange}
// onChange={newValue => {
// setFieldValue(field.name, newValue);
// console.log("newValue = " + newValue);
// }}
placeholder={props.placeholder}
/>
{touched[field.name] && errors[field.name] && (
<div className="error">{errors[field.name]}</div>
)}
I cannot find the right way to deal with the onChange, handleChange events from Formik and from myself. the lifting of the state up and the Formik validations are broken.
Can someone point me in the right direction for the correct syntax please ?
I have an antd form with multiple form items and try to find a way to mark the complete form as readonly. I could for sure set each input component to 'disabled' but I wonder if there is a convenient way to do so on the form via an API call that I do not know yet.
Wrapping the antd form inside a fieldset and setting this to 'disabled' works pretty well.
<fieldset disabled={editorDisabled}>
<Form>
...
<Form/>
<fieldset/>
I don't see such an option in the form api, and I think it's the rare use case, so I doubt it exists. However, you can simply add variable which will track the disabled status, i.e.:
const YourAwesomeComponent = (props) => {
const disabled = someLogicToCalculateTheDisabledStatus(props);
return <Form ...>
<Input disabled={disabled} ... />
<Select disabled={disabled} ... />
<Button disabled={disabled} ... />
</Form>
}
Hope it helps.
As of version 4.21.0 (Jun 6, 2022) the disabled prop can be used in the form to disable all fields, i.e.:
<Form disabled={true}>
...
</Form>
It is enforced as long as a <Form.Item/> isn't explicitly marked as not disabled with disabled={false}. You can see the reference in antd docs here.
I am trying to turn off autocomplete on an ant design Select but nothing I try works. This is obviously problematic as chromes (only one tested at this point) autocomplete completely covers the Select Options (Image below).
I am using antd in React and have tried the following on both the Select tag and Form tag:
autoComplete="off"
autoComplete="nope"
autoComplete="business-state"
and none of them seem to turn it off.
Here is a link to a code sandbox with almost the same code but the problem is it does not reproduce the same issue. For some reason the exact same code on sandbox doesn't show the autocomplete. I added an email input to show to test if autocomplete works on that and sure enough it does. I am at a loss for why this is working differently in sandbox than from my server.
https://codesandbox.io/s/wovnzpl9xw
Here is what it looks like when a user is typing to search the Options
Here is what it should look like (it only looks like this on focus but as soon as a user types chrome shows autocomplete)
Figured out a solution to my question, thanks to #trkaplan for pointing me in the right direction. Not the most elegant solution I am guessing so if anyone else has a better way to implement this I am all ears. I essentially had to create an onFocus method for the Select that grabs all of the elements with class ant-select-search__field loops through them and utilize setAttribute to change the autocomplete attribute to an arbitrary value in order to disable it.
onFocus={() => {
if (!this.state.autocompleteDisabled) {
let i;
const el = document.getElementsByClassName(
"ant-select-search__field"
);
for (i = 0; i < el.length; i++) {
el[i].setAttribute(
"autocomplete",
"registration-select"
);
}
this.setState({ autocompleteDisabled: true });
}
}}
I have applied to add the autocomplete="none" into the Select and it is looking fine.
<Select
showSearch
optionFilterProp="children"
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
onSearch={onSearchZipCode}
filterOption={(input, option) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
placeholder="Choose a City"
autoComplete="none"
// disabled={true}
>
{cities.map((city) => (
<Select.Option key={city.id} value={city.id}>
{city.name}
</Select.Option>
))}
</Select>;
You could also use AutoComplete instead of Select, because with this it's possible to change the underlying Input
<AutoComplete ... >
<Input autoComplete='off' id='myId' />
</AutoComplete>
AutoComplete is "new" and intended to be used if you are fetching data for the input instead of the data being static, but essentially its just a copy of Select and could be used the same way.
Another thing that worked very well for me was the following:
<FormItem>
<Select
autoComplete="new-state"
{...otherProps}
/>
</FormItem>
The autoComplete prop currently isn't documented properly and they don't even cater for TS users properly.
But this worked, if you've got that new word in the autoComplete prop, Chrome (and hopefully other browsers) will ignore that field.
For TypeScript users that have justifiably strict type rules:
<Select
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
autoComplete="new-state"
{...otherProps}
/>
You have to set filterOption to false
See this code sandbox
The only "clean" way I found to have no autocomplete when the label of the input is supposed to be aucompleted according to chrome (see here: Which Attributes Does Chrome Autofill Expect?) is to modify the labels by inserting invisible character in the label
<Form.Item label={<>Country</>}>
for example will be interpreted as
<Form.Item label={<>Country</>}>
But chrome does not recognize it as a Country input field
In my project I had dynamic inputs so the solution was (using _.times):
<Form.Item key={id} label={_.times(name.length, num => <>{tag.name.charAt(num)}</>)}>
Hacky but future proof (I hope)
Going to the FormItem component you can set the name props to "stateEnum" and then your browser won't just assume the field name from the label.
It works nicely for me on Google Chrome.
Example:
<FormItem label="State" name="stateEnum">
...
</FormItem>