I have a problem creating two checkbox in javascript and checking if none is clicked, an error appears in the form field, and at least one checkbox must be clicked, if one is clicked there will not be an error in the form field .
I'm using VueJs 2
<div class="d-flex">
<v-checkbox
v-model="checkboxOptionHydro"
:rules="checkboxPermissionRules.required"
class="ml-3 secondary--text"
label="Hydro"
color="accent"
required
/>
<v-checkbox
v-model="checkboxOptionWind"
:rules="checkboxPermissionRules.required"
class="ml-3 secondary--text"
label="Wind"
color="accent"
required
/>
</div>;
data: () => ({
checkboxPermissionRules: { required: v => !!v || "error you need to choose one of the options" },
})
You should just be able to use your v-model reference in whatever function submits your form. For example, if you button that submits your form, add an v-on:click to your function. The validation can happen inside that function before the form gets submitted.
<button v-on:click="submitForm">Submit<button>
In your methods:
function submitForm(){
//validation
if (!checkboxOptionHydro && !checkboxOptionWind){
//add error to data
this.checkboxError = true;
}
}
And then just add an element(p tag with red font or whatever) under the checkbox in your form to display the error if this.checkboxError is true.
Does that help?
Related
I have a form with two fields name and age. I know when user fill these two fields and hit the submit button I can get the values for these two fields.
But what I want is, I have a button call show filled values. When your press that button I want to see the user-filled values in the form. For example, if he fills name as 'Tom' and age as 85. I want to see that. But right now what I am getting is the empty initial values object.
My Code
How do I achieve this using Reactjs?
U can get the filled fields using Formiks props provided by the Formik.
The values prop provided by the formik will gives the filled fields values. Initially it will be the empty object . After you start filling the fields, the values object will be updated accordingly.
To know more What Props can Formik provide ?
visit :- https://formik.org/docs/api/formik#touched--field-string-boolean-
Hope the below code snippet will be useful for you.
<Formik
initialValues={{}}
validationSchema={() => Yup.object().shape({`enter your validation keys here`})}
onSubmit={(values) => {
console.log('values after submit', values);
}}
>
{(formikProps) => {
const { values, handleChange } = formikProps;
return (
<Form>
<label>
name
<input name="name" onChange={handleChange} />
</label>
<label>
age
<input name="age" type="number" onChange={handleChange} />
</label>
<button
type="button"
onClick={() => {
console.log('show filled fields', values);
}}
>
Show Filled Fields
</button>
<button type={'submit'}> Submit</button>
</Form>
);
}}
</Formik>
So I am trying to perform live form validation using React.
I have a radio button that asks the user if he already has an existing website. If his answer is yes, I need to validate the existing website text input. If the answer is no, I need not validate the existing website field and allow the user to submit.
this.state.redesign is controlled by the radio buttons yes and no.
In componentDidUpdate, I check if redesign has changed. If it has, I perform validation again by calling this.validate('existing_website').
The validate function checks if this.state.redesign is true and this.state.exsting_website == "". If yes, then it sets validation_error to true for that input field.
I am unable to achieve the desired result. When I click on the "Yes" radio button, the submit button still remains active.
In can see that when I click "Yes" componentDidUpdate is called and so is this.validate('existing_website').
The line
this.setState({[input_name]:input},()=>{
console.log(this.state[input_name]);
});
in the validate function also logs the updated state where I see this.state.existing_website.validation_error is set to true.
But the component does not rerender after this and the button remains active.
Any idea why this is happening? Please help me out guys! Thanks a lot in advance. Below is my full code.
constructor(props){
super(props);
this.state={
existing_website:{value:'',validate:true,validation_error:false,validation_message:"This field is necessary if you have selected yes above."},
redesign:false
}
this.validate = this.validate.bind(this);
}
getLabelAndInput(label,type,input_name){
var field= <input type={type} name={input_name} value={this.state[input_name].value} onChange={(e)=>this.setInputValue(input_name,e.target.value)} onBlur={()=>this.inputBlur(input_name)} onFocus={()=>this.inputFocus(input_name)} className="width-100"/>
return (
<div className={"form-group"}>
<label>{label}</label>
{field}
{this.state[input_name].validation_error?
<p className="error">{this.state[input_name].validation_message}</p>
:
''
}
</div>
);
}
validate(input_name){
var input = Object.assign({},this.state[input_name]);
if(input.validate){
if(input_name=="existing_website"){
if(this.state.redesign && input.value==""){
console.log('existing website validation error')
input.validation_error = true;
}
else{
console.log('existing website no validation error')
input.validation_error = false;
}
}
}
this.setState({[input_name]:input},()=>{
console.log(this.state[input_name]);
}); // Is this line mutating the state??
}
componentDidUpdate(prevProps,prevState){
if(prevState.redesign != this.state.redesign){
console.log('redesign change')
this.validate('existing_website');
}
}
render(){
console.log(this.state.existing_website.validation_error);
let btnSubmit = <button type="button" className="btn btn-primary" onClick={()=>this.handleSubmit()}>Submit</button>
if(this.state.existing_website.validation_error){
btnSubmit = <button type="button" className="btn btn-secondary" disabled>Submit</button>
}
return(
<div className="form-group">
<label className="highlight">Do you already have a website?</label>
<span onClick={()=>this.setState({redesign:false},()=>{this.likedWebsitesRef.current.focus()})}><input type="radio" name="redesign" checked={!this.state.redesign}/> <span className="service_type_text">No</span></span>
<span onClick={()=>this.setState({redesign:true})}><input type="radio" name="redesign" checked={this.state.redesign}/> <span className="service_type_text">Yes</span></span>
</div>
{ this.state.redesign &&
<div className="form-group">
{this.getLabelAndInput('Link to existing website','text','existing_website')}
</div>
}
{btnSubmit}
);
}
Edit:
My console.log outputs:
The boolean values below are from the console.log in the render function and indicate the value of this.state.existing_website.validation_error.
false // first rerender because of change in this.state.redesign
redesign change // console.log in componentDidUpdate due to above change
existing website validation error // validate function is called
false // render again.this was meant to happen after this.setState while console.logs below
{value: "", highlight: true, validate: true, validation_error: false, validation_message: "This field is necessary if you have selected yes above."}
//no rerender after this!
I'm having an input validation problem thats allowing the form to submit without having any selectorValues added. The check I have seems to only check for input inside the textarea but doesn't account for the Add button being pressed.
Here's a sandbox reproducing the issue.
I'm using Semantic-ui-react so my <Form.Field /> looks like this:
<Form.Field required>
<label>Selector Values:</label>
<TextArea
type="text"
placeholder="Enter selector values 1-by-1 or as a comma seperated list."
value={this.state.selectorValue}
onChange={this.handleSelectorValueChange}
required={!this.state.selectorValues.length}
/>
<Button positive fluid onClick={this.addSelectorValue}>
Add
</Button>
<ul>
{this.state.selectorValues.map((value, index) => {
return (
<Card>
<Card.Content>
{value}
<Button
size="mini"
compact
floated="right"
basic
color="red"
onClick={this.removeSelectorValue.bind(this, index)}
>
X
</Button>
</Card.Content>
</Card>
);
})}
</ul>
</Form.Field>
So in the above, <TextArea> has a required prop: !this.state.selectorValues.length. This is only checking for input inside the textarea, it should check that the value has been added by pressing the Add button before allowing the form to submit.
In your addSelectorValue add a check to see if this.state.selectorValue it not empty, if it is just return, this will prevent adding empty values to selectorValues
addSelectorValue = e => {
e.stopPropagation();
e.preventDefault();
if (!this.state.selectorValue) return;
//continue if this.state.selectorValue has a value
};
Before submitting add a check to see if this.selectorValues is empty, if so focus on textarea.
To focus we need to first create a ref to our textarea.
Create a ref to be
attached to a dom element
textareaRef = React.createRef();
// will use our ref to focus the element
focusTextarea = () => {
this.textareaRef.current.focus();
}
handleSubmit = () => {
const { selectorValues } = this.state;
if (!selectorValues.length) {
// call our focusTextarea function when selectorValues is empty
this.focusTextarea();
return;
}
this.setState({ submittedSelectorValues: selectorValues });
};
// attach our ref to Textarea
<Textarea ref={this.textareaRef} />
After some search ... required prop is for decorational purposes only - adding astrisk to field label.
It has nothing to form validation. You need a separate solution for that - try formik or set some condition within submit handler.
Formik plays nicely with yup validation schema - suitable for more complex, dynamic requirements.
I am using Redux forms with multiple submit buttons along with redux-form <Field />. I need to control the validation of these fields based on click of these buttons. For ex. I need to set a flag to True/False based on click of these buttons so that I can conditionally validate my fields like below:
<Field
name="date"
component={DateFormField}
validate={isSaveDraft && [validateRequiredText]}
floatingLabelText="Date"
fullWidth
helpText="blablabla"
/>
<Field
name="title"
component={TextFormField}
normalizeOnBlur={normalizeTextOnBlur}
validate={!isSaveDraft && [validateRequiredText]}
floatingLabelText="Project title"
fullWidth
helpText="blablabla"
/>
As you can see from above code, I'm conditionally validating my fields with validate={isSaveDraft && [validateRequiredText]} and validate={!isSaveDraft && [validateRequiredText]}
Here are my two submit buttons:
<RaisedButton
label={submitting ? 'Saving Draft...' : 'Save Draft'}
type="button"
onClick={handleSubmit(values => onSubmit())}
disabled={submitting}
primary
/>
<RaisedButton
label={submitting ? 'Submitting Brief...' : 'Submit Brief'}
type="button"
onClick={handleSubmit(values => onSubmit())}
disabled={submitting}
primary
/>
However, I'm not able to achieve it. Please help.
After a lot of headaches and head scratching, I've finally found the solution without making things look ugly. Thanks to a fellow developer for this solution. Original idea was to set a flag on click of the button and conditionally validate the fields. (PS: I'm using Field Level Validations). However, the issue was that the validations are being executed BEFORE the flag setting as the onClick handler wouldn't fire before all the validations are fixed and that logic is buried deep inside redux-forms (perks of unnecessarily overcomplicating simple things by using a library).
Here is the solution:
submit handler
handleSubmit() {
const { bookingCreate, modalShow, navigateTo } = this.props;
const { isDraftAction } = this.state; // my flag
// create record!
return bookingCreate(isDraftAction)
.then(responsePayload => {
...
})
.catch(handleSubmissionError);
}
isDraftAction is the flag which is set (in local state) when the action is called on onClick of both buttons.
My conditional Field level validations
<Field
name="date"
component={DateFormField}
validate={isDraftAction && [validateRequiredText]}
fullWidth
helpText="blablabla"
/>
<Field
name="title"
component={TextFormField}
normalizeOnBlur={normalizeTextOnBlur}
validate={!isDraftAction && [validateRequiredText]}
fullWidth
helpText="blablabla"
/>
My 2 buttons for SAVE RECORD and SUBMIT RECORD.
const submit = handleSubmit(values => onSubmit()); // this is redux-form's submit handler which will in-turn call my own submit handler defined above. (That's where the library hides all the logic and makes developer helpless)
<RaisedButton
label={submitting && isDraft ? 'Saving Draft...' : 'Save Draft'}
type="button"
onClick={() => {
this.props.dispatchAction({ draftAction: true }).then(() => {
submit();
});
}}
disabled={submitting}
primary
/>
<RaisedButton
label={submitting && !isDraft ? 'Submitting Brief...' : 'Submit Brief'}
type="button"
onClick={() => {
this.props.dispatchAction({ draftAction: false }).then(() => {
submit();
});
}}
disabled={submitting}
primary
/>
dispatchAction() is my action function which will FIRST set the flag to true/false THEN call redux-forms inbuilt submit handler. Also, I've extracted the redux-form's submit handler as it is above only for more clarity.
dispatchAction()
dispatchAction={({ draftAction }) =>
new Promise(resolve => {
this.setState({ isDraftAction: draftAction }, resolve);
})
}
use a state variable as isSaveDraft and set it default to false
Add onClick action of button to set state.isSaveDraft = true
validate={(isSaveDraft && [validateRequiredText]} will not work since validate expects a function all the time. Also, field level validation happens onTouch, or onBlur etc. which is way too early as you won't know which button will be clicked.
What you need to do is use a extra flag prop to hold which button was clicked and then use that in the form level validation.
So your Fields will look like this (no more Field level validation):
<Field
name="date"
component={DateFormField}
floatingLabelText="Date"
fullWidth
helpText="blablabla"
/>
...
<RaisedButton
label={submitting ? 'Saving Draft...' : 'Save Draft'}
onMouseDown={() => this.setDraftFlag(true)}
...
/>
<RaisedButton
label={submitting ? 'Submitting Brief...' : 'Submit Brief'}
onMouseDown={() => this.setDraftFlag(false)}
...
/>
I'm using onMouseDown to capture the flag since you're already using onClick for submitting the form. Besides, we need to do the validation before submit anyway.
And then in your form's validate (based on SyncValidation example)
const validate = values => {
const errors = {}
const {isDraft, ...rest} = values
if(isDraft) {
// draft validations
} else {
// other validations
}
return errors
}
export default reduxForm({
form: 'myForm', // a unique identifier for this form
validate, // <--- validation function given to redux-form
})(MyForm)
setDraftFlag can be an action or you can make it part of your Form component like so (I find this easier since you already get change bound to your form):
setDraftFlag(value) {
this.props.change('isDraft', value));
}
How to validate input fields inside a modal popup using ParsleyJS?
I have already an error container in layout page which works for page level input fields. I want to validate input fields in a modal popup and the error message should also be displayed in the popup.
To display validation errors inside a specific the Modal, you will need to use this data attribute on the input elements:
data-parsley-errors-container="#modal_div_error_container"
This is how you can validate the input fields inside your Modal <div>
JS:
$(function(){
var parsley_valiation_options = {
//errorsWrapper: '',
errorTemplate: '<span class="error-msg"></span>',
errorClass: 'error',
}
//check if modal_div element exists on the page
if ($('#modal_div').length > 0) {
//Attach Parsley validation to the modal input elements
$('#modal_div input').parsley(parsley_valiation_options);
//On modal submit button click, validate all the input fields
$('#modal_div_submit_button').click(function(event) {
event.preventDefault();
var isValid = true;
$('#modal_div input').each(function(){
if($(this).parsley().validate() !== true)
isValid = false;
})
if(isValid) {
alert("All fields are validated !");
}
});
}
});
HTML:
<!-- Modal -->
<div id="modal_div">
<!-- Modal div error container (Validation error messages will display here)-->
<div id="modal_div_error_container"></div>
<label for="name">
Name (should be alphanumeric and min length: 7)
</label>
<input type="text" id="name" name="name" data-parsley-minlength="7" data-parsley-minlength-message="Name must be at least 7 characters" data-parsley-required="true" data-parsley-errors-container="#modal_div_error_container"/>
<button type="submit" id="modal_div_submit_button">Submit</button>
</div>
You need to use button type as a "submit" instead of "button". Then that might solve your issue.