Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trigger validations onSubmit vs onBlur option #93

Open
th3fallen opened this issue May 10, 2018 · 7 comments
Open

Trigger validations onSubmit vs onBlur option #93

th3fallen opened this issue May 10, 2018 · 7 comments

Comments

@th3fallen
Copy link

is this currently possible?

@mikelyncheski
Copy link

@th3fallen I am currently using formsy to only show the messages after a user leaves the input (instead of on typing). The validations are still done as the user types but I am only showing them after the user modifies the input or clicks the submit button. I control that in my input wrapper component by choosing when the error message gets displayed or not. Something like:

if (!this.state.isFieldEdited && !this.props.isFormSubmitted()) errorMessage = null;

Note that isFieldEdited is part of my component and isFormSubmitted() is from Formsy.

@MilosRasic
Copy link
Contributor

I've been wanting this for a long time too. What @mikelyncheski suggest is certainly possible and a good way to do it, but sometimes you may want to optimize a demanding validation by not doing it on every keyup. Debounce would also be another nice option. We could probably add this as a non-breaking change as a prop which works as before by default, something like:

<SomeFormsyComponent validateOn={'blur'} />

with 'keyup' as default, or whatever is the default atm

@MilosRasic
Copy link
Contributor

Ok, we're all stupid. Sorry for calling you stupid, but I'm calling myself stupid too so it's fine ;)

Upon further investigation turns out this is up to the implementation of a formsy field component. this.props.setValue provided by withFormsy has a secon parameter, boolean, which tells formsy whether to validate the new value or not. This altered example from readme does exactly what we need:

class MyInput extends React.Component {
  constructor(props) {
    super(props);
    this.changeValue = this.changeValue.bind(this);
    this.validateValue = this.validateValue.bind(this);
  }

  changeValue(event) {
    // setValue() will set the value of the component, which in
    // turn will validate it and the rest of the form
    // Important: Don't skip this step. This pattern is required
    // for Formsy to work.
    this.props.setValue(event.currentTarget.value, false);
  }

  validateValue(event) {
    this.props.setValue(event.currentTarget.value);
  }

  render() {
    // An error message is returned only if the component is invalid
    const errorMessage = this.props.getErrorMessage();

    return (
      <div>
        <input
          onChange={this.changeValue}
          onBlur={this.validateValue}
          type="text"
          value={this.props.getValue() || ''}
        />
        <span>{errorMessage}</span>
      </div>
    );
  }
}

@ghost ghost mentioned this issue Jul 23, 2018
@djensen47
Copy link

djensen47 commented May 29, 2019

As a followup on this one. When you use onBlur to set the error, a common pattern is to clear the error when the user starts typing.

  1. Enter invalid value
  2. Blur the field
  3. Error appears
  4. Change the value in the field
  5. Error message goes away
  6. Blur the field
  7. Validation occurs again

Right now, it seems that Formsy does not internally handle steps 4-5, correct.

@hungbang
Copy link

Is there any solution for this issue?
we actually need to trigger validations onSubmit and onBlur , it's really needed

@rkuykendall
Copy link
Member

@hungbang There is currently no solution for this issue, but PRs are welcome as well as failing tests or even just edits to API.md with the desired feature spec. I think anyone will find the project very easy to work with.

@rkuykendall rkuykendall changed the title Trigger validations onSubmit vs onBlur option? Trigger validations onSubmit vs onBlur option Feb 22, 2020
@aqos156
Copy link

aqos156 commented Mar 14, 2020

Hi, I wanted to implement this behavior so I went through the source code of formsy and came up with this solution, but I don't know much about the structure and the way formsy validates the forms in it's internals (frankly don't have that much time), but it seems to be working as expected.

That's why i wanted to ask @rkuykendall if this is a possible proof of concept that could be implemented.

ValidationInput.js

import { withFormsy } from "formsy-react";
import React from "react";
class ValidationInput extends React.Component {
  constructor(props) {
    super(props);
    this.changeValue = this.changeValue.bind(this);
    this.validateValue = this.validateValue.bind(this);
  }

  changeValue(event) {
    
   // this is an add method via the InputWrapper
   // that resets the validation properties if an error 
   // is present
    if (this.props.showError) {
      this.props.resetValidation();
    }

    // setValue() will set the value of the component, which in
    // turn will validate it and the rest of the form
    // Important: Don't skip this step. This pattern is required
    // for Formsy to work.
    if (this.props.isValidValue(event.currentTarget.value)) {
      this.props.setValue(event.currentTarget.value);
    } else {
      this.props.setValue(event.currentTarget.value, false);
    }
  }

  validateValue(event) {
    this.props.setValue(event.currentTarget.value);
  }

  keyDown = event => {
    // If we press enter, we want to validate the input (omitting
    // the false argument)
    if (event.keyCode == "13") {
      this.props.setValue(event.currentTarget.value);
    } 
  };

  render() {
    // An error message is returned only if the component is invalid
    const {
      errorMessage,
      className,
      showRequired,
      isFormSubmitted,
      showError,
      type,
      value,
      placeholder,
      children
    } = this.props;

    let nClassName = className ? className : "form-control";

    nClassName =
      isFormSubmitted && showRequired
        ? nClassName + " is-invalid"
        : showError
        ? nClassName + " is-invalid"
        : nClassName;

    return (
      <fieldset className="form-group">
        <input
          className={nClassName}
          type={type ? type : "text"}
          value={value}
          onChange={this.changeValue}
          onBlur={this.validateValue}
          placeholder={placeholder}
          onKeyDown={this.keyDown}
        />
        {children ? children : null}
        {errorMessage ? (
          <div className="invalid-feedback">{errorMessage}</div>
        ) : null}
      </fieldset>
    );
  }
}

class WrappedInput extends withFormsy(ValidationInput) {
  resetValidation = () => {
    const { pristineValue } = this.state;
    const { validate } = this.context;

    this.setState({
      isPristine: true,
      isValid: true
    });
  };

  render() {
    const { innerRef } = this.props;
    const propsForElement = {
      ...this.props,
      errorMessage: this.getErrorMessage(),
      errorMessages: this.getErrorMessages(),
      hasValue: this.hasValue(),
      isFormDisabled: this.isFormDisabled(),
      isFormSubmitted: this.isFormSubmitted(),
      isPristine: this.isPristine(),
      isRequired: this.isRequired(),
      isValid: this.isValid(),
      isValidValue: this.isValidValue,
      resetValue: this.resetValue,
      setValidations: this.setValidations,
      setValue: this.setValue,
      showError: this.showError(),
      showRequired: this.showRequired(),
      value: this.getValue(),
      resetValidation: this.resetValidation
    };

    if (innerRef) {
      propsForElement.ref = innerRef;
    }

    return React.createElement(ValidationInput, propsForElement);
  }
}

export default WrappedInput;

And the form source code:

<Formsy onValidSubmit={this.submitForm}>
  <ValidationInput
    name="email"
    validations="isEmail"
    validationError={strings.form.errors.emailFormat}
    placeholder={strings.auth.email}
    required
  />
  <div className="text-center">
    <button
      className="btn btn-primary pull-center w-50 mt-5"
      type="submit"
      disabled={this.props.inProgress}
    >
      {strings.auth.login}
    </button>
  </div>
</Formsy>

EDIT

Added onKeyDown check for validation of the input on enter key press

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants