Form Validation not working using react and StepWizard - reactjs

Can someone explain why this validation is not working properly? When I click the submit button I should check to see if the field is empty, if it is it should display the error and prevent the next page. If the form has been filled in, then no message should display and clicking the button will take you to a new screen. Currently, the error displays whether or not the field is filled in and the page does not advance in either case.
import React, { Component } from 'react'
const intialState = {
account: "",
accountError: ""
};
export class LandingPage extends Component {
state = intialState;
handleChange = event => {
this.setState({
})
}
continue = e => {
e.preventDefault();
this.props.nextStep();
}
validate = () => {
let accountError= "";
if (!this.state.name) {
accountError = "You must enter an account number!";
}
if (accountError) {
this.setState({ accountError });
return false;
}
return true;
};
handleSubmit = event => {
event.preventDefault();
const isValid = this.validate();
if (isValid) {
console.log(this.state);
this.setState(intialState);
}
};
previous = e => {
e.preventDefault();
this.props.previousStep();
}
render() {
const { values } = this.props;
const { errors } = this.props;
return (
<div>
<h1>Enter an account number</h1>
<input
type="text"
required="required"
placeholder="Enter Account Number"
autoComplete='off'>
</input>
<div className="footer">
<button onClick={this.validate}>Submit</button>
</div>
<div>
{this.state.accountError}
</div>
</div>
)
}
}
export default LandingPage;

The issue is that the name in the state was not getting any value. Fix it like below.
Change the initialState to have the name field
const intialState = {
...
...
name: ""
};
handleChange needs to set the value from the event.
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
Update the validate function to handle the case when input is typed.
validate = () => {
let accountError = "";
if (!this.state.name) {
accountError = "You must enter an account number!";
}
if (accountError) {
this.setState({ accountError });
return false;
}
this.setState({ accountError: "" });
return true;
};
Add the handleChange as the onChange to the input element.
<input
...
...
...
name="name"
onChange={this.handleChange}
></input>
Working Example

Related

React input tag disabled prop issue

I am trying to build a login form in React.js. I want to enable/disable Login button based on results return by validate method. React throws error 'Invalid value for prop disabled on tag. Either remove it from the element, or pass a string or number value to keep it in the DOM.'. Does anyone have came across same error? Help me to understand what is going wrong here?
import React, { Component } from "react";
import Input from "../common/input";
import Joi from "joi-browser";
class LoginForm extends Component {
state = {
account: {
username: "",
password: "",
},
errors: {},
};
schema = {
username: Joi.string().required().label("Username"),
password: Joi.string().required().label("Password"),
};
abortEarly = {
abortEarly: false,
};
handleSubmit = (event) => {
event.preventDefault();
const errors = this.validate();
if (errors) return;
console.log("submitted");
};
validate = () => {
const result = Joi.validate(
this.state.account,
this.schema,
this.abortEarly
);
const errors = {};
if (!result.error) return null;
result.error.details.map((detail) => {
errors[detail.path[0]] = detail.message;
return detail.path[0];
});
// console.log(errors);
this.setState({ errors });
return errors;
};
validateProperty = ({ name, value }) => {
const propertyTobeValidated = { [name]: value };
const schema = { [name]: this.schema[name] };
const { error } = Joi.validate(propertyTobeValidated, schema);
return error ? error.details[0].message : null;
};
handleChange = ({ currentTarget }) => {
const errors = { ...this.state.errors };
const error = this.validateProperty(currentTarget);
if (error) errors[currentTarget.name] = error;
else delete errors[currentTarget.name];
const account = { ...this.state.account };
account[currentTarget.name] = currentTarget.value;
this.setState({ account, errors });
};
render() {
const { account, errors } = this.state;
return (
<div>
<h1>Login</h1>
<form onSubmit={this.handleSubmit}>
<Input
label="Username"
name="username"
value={account.username}
onChange={this.handleChange}
error={errors.username}
></Input>
<Input
label="Password"
name="password"
value={account.password}
onChange={this.handleChange}
error={errors.password}
></Input>
<button disabled={this.validate} className="btn btn-primary">
Login
</button>
</form>
</div>
);
}
}
export default LoginForm;
Disabled is a boolean property, meaning it can only have a value of true or false. Instead of a boolean, your validate function is returning an object, thus React throws an "Invalid value" error. In order to fix this you could check if the result of this.validate is null:
<button
disabled={(this.validate() !== null)}
className="btn btn-primary"
>
Login
</button>
Also, you forgot to call your this.validate at all :)
Regarding the "Maximum update depth...", you should remove the this.setState from the this.validate, because you are already putting the error in state in the handleChange method.
Here you go with a solution
import React, { Component } from "react";
import Input from "../common/input";
import Joi from "joi-browser";
class LoginForm extends Component {
state = {
account: {
username: "",
password: "",
},
errors: {},
};
schema = {
username: Joi.string().required().label("Username"),
password: Joi.string().required().label("Password"),
};
abortEarly = {
abortEarly: false,
};
handleSubmit = (event) => {
event.preventDefault();
const errors = this.validate();
if (errors) return;
console.log("submitted");
};
validate = () => {
const result = Joi.validate(
this.state.account,
this.schema,
this.abortEarly
);
const errors = {};
if (!result.error) return false;
result.error.details.map((detail) => {
errors[detail.path[0]] = detail.message;
return detail.path[0];
});
// console.log(errors);
this.setState({ errors });
return true;
};
validateProperty = ({ name, value }) => {
const propertyTobeValidated = { [name]: value };
const schema = { [name]: this.schema[name] };
const { error } = Joi.validate(propertyTobeValidated, schema);
return error ? error.details[0].message : null;
};
handleChange = ({ currentTarget }) => {
const errors = { ...this.state.errors };
const error = this.validateProperty(currentTarget);
if (error) errors[currentTarget.name] = error;
else delete errors[currentTarget.name];
const account = { ...this.state.account };
account[currentTarget.name] = currentTarget.value;
this.setState({ account, errors });
};
render() {
const { account, errors } = this.state;
return (
<div>
<h1>Login</h1>
<form onSubmit={this.handleSubmit}>
<Input
label="Username"
name="username"
value={account.username}
onChange={this.handleChange}
error={errors.username}
></Input>
<Input
label="Password"
name="password"
value={account.password}
onChange={this.handleChange}
error={errors.password}
></Input>
<button disabled={this.validate} className="btn btn-primary">
Login
</button>
</form>
</div>
);
}
}
export default LoginForm;
validate method should return boolean (true or false)

Unable to update parent prop in react

I can insert the input value say "1,2,3" and when backspace it removes all but in the console "1" is still shown i.e., House{props{house{property{rent:1}}}}
I am providing the code here which has 3 files.
(1) house.js
import ValInput from "main/components/val-input";
class House extends Component {
state = {
rent:"",
};
componentDidMount() {
if (this.props.house.rent) {
const { rent} = this.props.house;
this.setState({ rent });
}
}
onChange = (e) => {
const rent = parseInt(e.target.value.replace(string);
this.setState({
rent,
});
};
render(){
const {house} = this.props;
const {rent} = this.state;
...
<ValInput
type="text"
value={ rent }
onChange={e => {
this.onChange(e);
}}
/>
}
(2) val-input\index.js
import React from "react";
import Input from "main/components/input";
const ValInput = props => (
<Input
{...props}
type={props.type ? props.type : "text"}
/>
);
export default valInput;
(3) components/input/index.js
import React from "react";
const noOp = () => {};
const Input = ({
onBlur = xP,
...otherProps
}) => (
<input
onBlur={e => {
e.target.placeholder = placeholder;
onBlur(e);
}}
{...otherProps}
/>
);
export default Input;
The expected result should be, after emptying the value say with backspace, and visit the page next time, the input field should be empty and should not show old value.
Check this CodeSandbox out I replicated your code and if I understood the problem right then fixed it
https://reactjs.org/docs/cross-origin-errors.html
For updating #NaderZouaoui, has given me an example how to do Call back :
1. Child file :
onChange={e => {
this.onChange(e);
}}
onChange = e => {
this.setState({
rent
});
this.props.callback(rent);
};
2. Parent file :
state = {
rent: ""
};
handleChangeRent = newRent => {
this.setState({ rent: newRent });
};
render(){
return(
<House house={{ rent }} callback={this.handleChangeRent} />
);
}

FormValidation with Button State

In my React app, I have a component call <ComingSoonForm/> Inside that, I have a TextInputField. If the Email valid, the Notify-Button is able. If the Email is invalid, the Notify-Button is disabled.
Here is my Component File:
import React, { Component } from "react";
import { TextInputField, toaster, Button, } from "evergreen-ui";
import Box from 'ui-box';
import { validateEmail } from "../FormValidation/FormValidator";
class ComingSoonForm extends Component {
constructor(props) {
super(props);
this.state = {
emailErr: {
status: true,
value: ""
},
email: "",
isDisabled: true,
};
this.handleSubmit = this.handleSubmit.bind(this);
this.checkFormStatus = this.checkFormStatus.bind(this);
}
handleEmailInput = e => {
const email = e.target.value;
this.setState({ email: email});
console.log(this.state.email);
this.checkFormStatus();
};
handleSubmit() {
if (this.checkFormStatus()) {
alert("Form is OK")
}
}
checkFormStatus() {
// form validation middleware
const { email } = this.state;
const emailErr = validateEmail(email);
if (!emailErr.status) {
this.setState({isDisabled:false})
return true;
} else {
this.setState({
emailErr,
});
return false;
}
}
render() {
return (
<div>
<Box className="welcomePageWelcomeInnerLoginButton">
<TextInputField
marginTop={15}
width={200}
onChange={this.handleEmailInput}
value={this.state.email}
type="email"
placeholder="Your email-address"
inputHeight={40}
/>
</Box>
<Button height="40" appearance="primary" marginBottom={5} className="welcomePageWelcomeInnerLoginButtonWidth" disabled={this.state.isDisabled} onClick={this.handleSubmit}>Notify Me</Button>
</div>
);
}
}
export default ComingSoonForm;
But this case doesn't work correctly. So when the command console.log(this.state.email) in the handleEmailInput Function run, I get the following data in the console:
I type one letter (t) and I get:
//ComingSoonForm.js:25
I type a second letter (t) and I get:
t //ComingSoonForm.js:25
t //FormValidator.js:10
Why do I have to enter two letters in order for one to appear in the console?
setState is asynchronous, you can pass a callback method as a second parameter like this:
handleEmailInput = e => {
const email = e.target.value;
this.setState({ email: email }, () => console.log(this.state.email));
this.checkFormStatus();
};

I use React js and Material-UI. How can i validate "correct" green color validation on button submit click?

Help,please. I use React js and Material-IU. I did "incorrect" red color textfield validation with errorText. How can i validate "correct" with green color on buttonsubmit click?
validate = () => {
const cardNumber = '1234567890123456'; //credit card form with 2 fields
const expiryNumber = '1234';
let isError = false;
const errors = {};
if (this.state.number != cardNumber) { //cardNumber validation
isError = true;
errors.numberError = 'failed';
}
if (this.state.expiry != expiryNumber) { //expiry validation
isError = true;
errors.expiryError = "failed";
}
if(isError) {
this.setState({
...this.state,
...errors
});
}
return isError;
}
onSubmit = e => { // on Button submit
e.preventDefault();
const err = this.validate();
if (!err) {
this.setState({
number: "",
expiry: ""
});
console.log(this.state);
};
} // next will be render <TextField>
I tried using an extra field in the component state, successValidation, that I change in onSubmit depending on the validation outcome. I then used that state property to determine what style to pass on to underlineStyle (property of the TextField). Maybe not the cleanest solution (don't know) but as far as I can tell it works. You can see it in action in this JSFiddle demo.
By the way: It was a while since I used Material-UI, but they have pretty good documentation to refresh your memory. You can, for example, see all the props for TextField at the bottom of this page.
const { RaisedButton, MuiThemeProvider, getMuiTheme, TextField } = MaterialUI;
class Test extends React.Component {
state = {
value: 'good',
error: false,
successValidation: false
}
handleInputChange = (e, newValue) => {
// reset errors and validation as well
this.setState({
value: newValue,
error: false,
successValidation: false
});
}
isValid = () => {
const {value} = this.state;
return value != 'bad';
}
onSubmit = () => {
if(this.isValid()) {
this.setState({successValidation: true, error: false});
} else {
this.setState({error: true});
}
}
render = () => {
const {value, error, successValidation} = this.state;
const underlineStyle = successValidation ? { borderColor: 'green' } : null;
return (
<div style={{width: '50%', margin: '0 auto'}}>
<h3>The input "bad" will cause error</h3>
<h3>All other input will cause green underline on submit</h3>
<TextField
errorText={error ? 'Validation error!' : ''}
name="test"
value={value}
onChange={ this.handleInputChange }
underlineStyle={underlineStyle}
/>
<RaisedButton onClick={ this.onSubmit }>Submit</RaisedButton>
</div>
);
}
}
const App = () => (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<Test />
</MuiThemeProvider>
);
ReactDOM.render(
<App />,
document.getElementById('container')
);

How to use validate-state with react-bootstrap

I'm using react-bootstrap and I'm trying to validate a form using the validate-state option. I can't figure out how to use getValidationState() to return error when I submit a form which would turn the input field red. Currently when the form loads I get an error message in console ProfileCandidateForm.getValidationState ReferenceError: error is not defined.
If I remove getValidationState() I can submit the form and if it errors the returns the error to an alert box. I would like to change this to the validate-state in bootstrap.
Any help is appreciated. Still wrapping my head around React.
export default class ProfileCandidateForm extends Component {
constructor(props) {
super(props);
var profileCandidate = this.props.profileCandidate;
var firstName = profileCandidate && profileCandidate.name && profileCandidate.name.first;
this.state = {
firstName: firstName || "",
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
var profileCandidate = this.state;
insertProfileCandidate.call({profileCandidate}, (error) => {
if (error) {
alert(error.reason);
}
});
}
getValidationState() {
if (error) return 'error';
}
render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<FormGroup
validationState={this.getValidationState()}
>
<FormControl
type="text"
name="firstName"
value={this.state.firstName}
placeholder="First name"
onChange={this.handleChange}
/>
<FormControl.Feedback />
</FormGroup>
<FormGroup >
<Button type="submit">
Save
</Button>
</FormGroup>
</form>
)
}
}
ProfileCandidateForm.propTypes = {
profileCandidate: PropTypes.object.isRequired,
}
You need to reference the value (state) of the text field in the getValidationState() function. Then return null (for no visible validation), 'success' (for green visible validation), or 'error' (for red validation).
Here is one of my getValidationState funcs.
getValidationState() {
var value = this.state.value;
if (value===null || value==='') { return null; }
var valid = this._getValidity(value)
if (valid===true) {
return 'success';
} else {
return 'error';
}
}

Resources