Form validation with react and material-ui

ValidationEventsReactjsMaterial Ui

Validation Problem Overview


I am currently trying to add validation to a form that is built using material-ui components. I have it working but the problem is that the way I am currently doing it the validation function is currently being called on every state change in the input (i.e. every letter that is typed). However, I only want my validation to occur once the typing has stopped.

Given my current code:

class Form extends React.Component {

	state = {open: false, email: '', password: '', email_error_text: null, password_error_text: null, disabled: true};

	handleTouchTap() {
		this.setState({
			open: true,
		});
	}

	isDisabled() {
        let emailIsValid = false;
        let passwordIsValid = false;

        if (this.state.email === "") {
            this.setState({
                email_error_text: null
            });
        } else {
            if (validateEmail(this.state.email)) {
                emailIsValid = true
                this.setState({
                    email_error_text: null
                });
            } else {
                this.setState({
                    email_error_text: "Sorry, this is not a valid email"
                });
            }
        }

        if (this.state.password === "" || !this.state.password) {
            this.setState({
                password_error_text: null
            });
        } else {
            if (this.state.password.length >= 6) {
                passwordIsValid = true;
                this.setState({
                    password_error_text: null
                });
            } else {
                this.setState({
                    password_error_text: "Your password must be at least 6 characters"
                });
            }
        }

        if (emailIsValid && passwordIsValid) {
            this.setState({
                disabled: false
            });
        }
    }

	changeValue(e, type) {
		const value = e.target.value;
		const nextState = {};
		nextState[type] = value;
		this.setState(nextState, () => {
			this.isDisabled()
		});
	}

	login() {
		createUser(this.state.email, this.state.password);
		this.setState({
			open: false
		});
	}

	render() {

		let {open, email, password, email_error_text, password_error_text, disabled} = this.state;

		const standardActions = (
			<FlatButton
				containerElement={<Link to="/portal" />}
				disabled={this.state.disabled}
				label="Submit"
				onClick={this.login.bind(this)} 
			/>
		);

		return (
			<div style={styles.container}>
				<Dialog
					open={this.state.open}
					title="Enter Your Details to Login"
					actions={standardActions}
				>
					<span className="hint--right hint--bounce" data-hint="Enter in your email address">
						<TextField
							hintText="Email"
							floatingLabelText="Email"
							type="email"
							errorText={this.state.email_error_text}
							onChange={e => this.changeValue(e, 'email')} 
						/>
					</span>
					<br />
					<span className="hint--right hint--bounce" data-hint="Enter your password">
						<TextField
							hintText="Password"
							floatingLabelText="Password"
							type="password"
							errorText={this.state.password_error_text}
							onChange={e => this.changeValue(e, 'password')} 
						/>
					</span>
				</Dialog>
				<h1>VPT</h1>
				<h2>Project DALI</h2>
				<RaisedButton
					label="Login"
					primary={true}
					onTouchTap={this.handleTouchTap.bind(this)} 
				/>
			</div>
		);
	}
}

export default Form;

Is there a way that I can achieve my desired functionality, without making a major change to the code, or does it need to be completely refactored?

Validation Solutions


Solution 1 - Validation

Does the check have to happen after a certain delay? A solution that I think would suffice in most situations would be to split your code up a bit. Don't trigger your isDisabled() function in changedValue(). Instead have it run on the onBlur event instead.

Try this:

<TextField
  hintText="Password"
  floatingLabelText="Password"
  type="password"
  errorText={this.state.password_error_text}
  onChange={e => this.changeValue(e, 'password')}
  onBlur={this.isDisabled} 
/>

and then your function becomes:

changeValue(e, type) {
    const value = e.target.value;
    const nextState = {};
    nextState[type] = value;
    this.setState(nextState);
}

Solution 2 - Validation

Current Material-UI version doesn't use the errorText prop but there is still a way that you can use to display error and apply validation to the TextField in Material-UI.

We use the error(Boolean) property to denote if there is an error or not. Further to display the error text use helperText property of the TextField in the Material-UI, just provide it the error text you want to display.

Do it like:

<TextField
  value={this.state.text}
  onChange={event => this.setState({ text: event.target.value })}
  error={text === ""}
  helperText={text === "" ? 'Empty!' : ' '}
/>

Solution 3 - Validation

Simplest is to call form.reportValidity(). form can be obtained by calling event.currentTarget.form.

Solution 4 - Validation

This library that I had created, takes care of everything related to validating fields and it supports material-ui components as well...

To validate your fields, you just need to wrap you field component and you are done... saving a lot of effort in managing state yourself manually.

<Validation group="myGroup1"
    validators={[
            {
             validator: (val) => !validator.isEmpty(val),
             errorMessage: "Cannot be left empty"
            }, ...
        }]}>
            <TextField value={this.state.value}
                       className={styles.inputStyles}
                       style={{width: "100%"}}
                       onChange={
                        (evt)=>{
                          console.log("you have typed: ", evt.target.value);
                        }
              

     }/>

Solution 5 - Validation

You can use onblur text field event. It's triggered when input looses focus.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBeeNagView Question on Stackoverflow
Solution 1 - ValidationChrisView Answer on Stackoverflow
Solution 2 - ValidationiamakshatjainView Answer on Stackoverflow
Solution 3 - ValidationLokeView Answer on Stackoverflow
Solution 4 - ValidationVISHAL DAGAView Answer on Stackoverflow
Solution 5 - ValidationYurii KramarenkoView Answer on Stackoverflow