Is there any way to validate an input field in the redux form when the user enters a value? All my validation are working when I click out or press the submit button. I want my validations to run when the user is typing. My code for the field is this:
<div className="fieldRow noMargin">
<Field
id={FIRST_TIME_OTP_NUMBER}
name={FIRST_TIME_OTP_NUMBER}
component={InputTextField}
className="text xxs"
classNameInvalid="text xxs error"
/>
</div>
You can check if field is active from metadata(props under the meta key), and show error if its value is true.
const renderField = ({input, label, type, meta: {active, touched, error, warning}}) => (
<div>
<label>{label}</label>
<div>
<input
{...input}
placeholder={label}
type={type}
onFocus={input.onFocus}
/>
{(active || touched) &&
((error && <span>{error}</span>) ||
(warning && <span>{warning}</span>))}
</div>
</div>
);
NOTE: It will only work if you are passing onFocus to your input element.
Codesandbox demo
Related
I have a form where if a certain radio option is selected I want to render a number input box, which should be required if the radio option is selected.
Here is my YUP schema for the relevant inputs:
areSeatsLimited: yup.string().required(),
numOfSeats: yup
.number()
.positive("This field must contain a positive number")
.integer("This field should contain an integer")
.when("areSeatsLimited", {
is: "yes",
then: yup.number().required().typeError("The field must contain a number"),
otherwise: yup.number().notRequired().typeError("The field must contain a number"),
}),
This works in a sense that if I open the form for the first time and dont choose the option that seats are limited, upon submitting I get no error from the numOfSeats input, which is expected since its not required.
However, if I check the seats are limited, then it gives me the error, which is also expected since its now required. But here is the problem: when I check that seats are unlimited again after selecting that they are limited. It still throws me the error as if the field is required. Also note its throwing me the typerror message("The field must contain a number")
Here is the react code for that part of the form
<div className="radio" style={{ display: "block", marginTop: "10px" }}>
<input
value="no"
type="radio"
id="unlimited"
{...register("areSeatsLimited")}
checked={areSeatsLimited === "no" || areSeatsLimited === undefined ? true : false}
/>
<label htmlFor="unlimited">Unlimited</label>
</div>
<div className="radio" style={{ display: "block", marginTop: "10px" }}>
<input
value="yes"
type="radio"
id="limited"
{...register("areSeatsLimited")}
checked={areSeatsLimited === "yes" ? true : false}
/>
<label htmlFor="limited">Limited</label>
</div>
{areSeatsLimited === "yes" ? (
<div className={`form-group required ${errors?.numOfSeats?.message ? "has-error" : ""}`}>
<label htmlFor="numOfSeats">Number Of Seats</label>
<input
type="number"
id="numOfSeats"
className="form-control"
placeholder="Amount of available seats..."
{...register("numOfSeats")}
/>
{errors?.numOfSeats?.message ? (
<span style={{ color: "var(--input-error-text-color)" }}>{errors.numOfSeats.message}</span>
) : (
""
)}
</div>
I have a similar set of fields but with string, and it works as expected.
This should solve your problem:
otherwise: number().transform(() => {
return undefined;
}).nullable().notRequired(),
An input field, according to this guy here, will return an empty string if you don't provide input, that is why it is throwing typeError. So you need to manually force it to return undefined when the seats are unlimited.
I'm having some problem to use errors (object provided by React Hook Form) to show a validation message (when a required input field is empty) for the input fields.
{
inputs.map((name) => (
<div key={name}>
<div style={{ marginTop: "3px" }}>
<input
name={`Chamfer Set.${name}`}
ref={register({ required: true })}
/>
</div>
{errors[`Chamfer Set.${name}`] && (
<span>Please enter a value for {name}.</span>
)}
</div>
));
}
Basically I have to link errors to the input name attribute, which in this case I'm using template literals. But it is not working and I guess it is something related to the literals, but I'm not very into it. Do you guys have any idea?
If I use console.log(errors), I have the following structure:
To access the error property just replace:
errors[`Chamfer Set.${name}`]
By:
errors["Chamfer Set"] && errors["Chamfer Set"][`${name}`]
As #Micheal mentioned, Try
{
inputs.map((name) => (
<div key={name}>
<div style={{ marginTop: "3px" }}>
<input
name={`Chamfer Set.${name}`}
ref={register({ required: true })}
/>
</div>
{errors[`Chamfer Set`][`${name}`] && (
<span>Please enter a value for {name}.</span>
)}
</div>
));
}
I would like to submit a step of wizard form on click of radio button instead of classic submit button.
Radio component :
const Radio = ({ input, children }) => (
<label className="form-radio city">
<input {...input} />
<span className="radio-text">{children}</span>
</label>
)
My class :
<ProfileForm.Page>
{CITIES.map(({ name }) => (
<Field component={Radio} type="radio" name="city" key={name} value={name}>
{name}
</Field>
))}
<button type="submit"></button>
</ProfileForm.Page>
This worked when I use the submit button but I want to remove it and submit city directly on click on the radio button.
I tried to had an onChange event with "this.form.submit()" but I cannot acced to "form".
I have a parent component ProfileForm.jsx with :
<Form validate={this.validate} onSubmit={this.handleSubmit} initialValues={values}>
{({ handleSubmit, invalid, pristine, values }) => (
<form onSubmit={handleSubmit}>
{activePage}
</form>
)}
</Form>
and my radio buttons are on the "active page" City.jsx with the code of my first post
I have a react component which has a input field with disable attribute. On click of the component, the input gets enabled and user can type on the field. I'm able to achieve till there, but I need to focus on input field on getting enabled.
Attributes.js
basicAmenitiesList.map(function(item, index){
return <Attribute key={index}
name={item.amenity_id}
type={item.title}
icon={item.icon}
selected={item.isSelected}
value={item.value}
onClick={_this.handleClick.bind(this)}
onChange={_this.handleChange.bind(this)}/>
})
The Attribute file :
<div onClick={this.handleClick.bind(this)}>
...
<input type="text" name={this.props.name}
ref={this.props.name}
placeholder="NO INFO FOUND"
value={this.props.value}
disabled={!this.props.selected}
onChange={this.props.onChange}
/>
</div>
handleClick(e) {
// I need to focus on enabling., that is when **this.props.selected** is true.
return this.props.onClick(this.props.name);
}
UPDATE
I tried onFocus for input,
onFocus(){
this.refs.pets.focus();
}
Right now I'm hard coding the refs name as pets, but is there any way to make it dynamic by sending the name with the onFocus?
you can use autoFocus as property for input
<input type="text" name={this.props.name}
ref={this.props.name}
placeholder="NO INFO FOUND"
value={this.props.value}
disabled={!this.props.selected}
onChange={this.props.onChange}
autoFocus
/>
I have a page which has a form in it named as profile updation and when a user comes to this page for any updation of his profile that time he only update 1 or 2 fields so every time form checks the form is valid or not then only saves in db, but I want to save if password and confirm password fields are not updated then also update his profile, but also when he wants to change password that time save button will get disabled and checks validation after that update the profile.
Means when user update only name that time also update the profile and also user update the password that time first check validation and then update the profile.
Save and isValid check:
app.controller('DemoCtrl', function($scope, $http) {
$scope.saveProfile = function(){
if($scope.profile.$valid){
ngProgress.start();
user.saveProfile($scope.currentUser.details,function(response){
angular.copy(response,shared.data.currentUser);
notification.success($filter("il8n")("_ProfileUpdateMessage_"));
ngProgress.done();
});
}
}
$scope.isValidForm = function(){
//if(($scope.profile.confirmpassword && $scope.profile.newpassword && $scope.profile.newpassword.$modelValue !== $scope.profile.confirmpassword.$modelValue))
// return true;
if(!$scope.profile.$valid){
if(($scope.profile.confirmpassword && $scope.profile.newpassword && $scope.profile.confirmpassword.$modelValue && $scope.profile.newpassword.$modelValue && ($scope.profile.newpassword.$modelValue.length == 0 || $scope.profile.confirmpassword.$modelValue.length == 0))){
return false;
}
if(($scope.profile.confirmpassword && $scope.profile.newpassword && $scope.profile.confirmpassword.$modelValue && $scope.profile.newpassword.$modelValue && $scope.profile.newpassword.$modelValue === $scope.profile.confirmpassword.$modelValue)){
return false;
}
}
if($scope.profile.$valid && $scope.profile.$dirty)
return false;
if($scope.profile.newpassword.$invalid || $scope.profile.newpassword.$dirty && $scope.profile.confirmpassword.$invalid || $scope.profile.confirmpassword.$dirty){
//$scope.profile.newpassword.$valid;
//$scope.profile.confirmpassword.$valid;
return false;
}
//if($scope.profile.newpassword.empty && $scope.profile.confirmpassword.empty ){
// return true;
//}
return true;
}
});
Find plnkr here.
As I see it, you want form where user can update few fields then update them?
About password change, I think you should split profile information from password change into two separate forms, where user can change password without changing other data. Then if user wants to change other user data (which is binded to ng-model and placed already into text boxes), then user change data and saves them.
Problem solved. If u want so, i can try to edit your plunk and show how it would look like :)
Plunk - New format
<form ng-submit="SAVE FUNCTION HERE">
<fieldset>
<div class="row">
<div class="col-sm-4">
<label class="proxima-nova nova-bold form-label">Change Password</label>
</div>
</div>
<div class="row">
<div class="col-sm-3">
<label data-ng-class="{'state-error': profile.newpassword.$invalid && profile.newpassword.$dirty && profile.newpassword.$error.strongPassword}">
<input type="password" class="form-control" placeholder="Enter new password" data-ng-model="currentUser.details.password" name="newpassword" data-password-check="currentUser.details.password" />
</label>
<div class="ng-cloak invalid" data-ng-show=" profile.newpassword.$error.strongPassword && profile.newpassword.$dirty && profile.newpassword.$invalid">
Password should contain atleast one special character, number, uppercase letter, and atleast 8 characters.
</div>
</div>
<div class="col-sm-3">
<label data-ng-class="{'state-error': profile.confirmpassword.$dirty && currentUser.details.password != currentUser.details.password_confirmation}">
<input type="password" class="form-control" placeholder="Confirm password" data-ng-model="currentUser.details.password_confirmation" name="confirmpassword" />
</label>
<div class="ng-cloak invalid" data-ng-show="profile.confirmpassword.$dirty && currentUser.details.password != currentUser.details.password_confirmation">
Passwords do not match
</div>
</div>
</div>
</fieldset>
</form>
Also in form fieldset you can add save button with type="submit", then that button will call that function which is defined into form tag
<form ng-submit="SAVE FUNCTION HERE">