horprogs / Just-validate

Modern, simple, lightweight (~5kb gzip) form validation library written in Typescript, with no dependencies (no JQuery!). Support a wide range of predefined rules, async, files, dates validation, custom error messages and styles, localization. Support writing custom rules and plugins.

Home Page:https://just-validate.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

fix: revalidateField does not trigger promise validation directly

kokoal opened this issue · comments

In some cases we want to validate a particular form field on an user action first without validating all form fields. And do final validation on fomr submit.

As for an exemple you have a promo code field you want to validate when the user click on a "Apply" button this will trigger a fetch (with Promise) validator and only validate the field containing the promo code.

In this case I try using revalidateField but it seems to not run the promise and always return true.

My full example :

applyPromoCodeButton.addEventListener('click', clickApplyButton);

let promotionalCodeError = '';
const getPromotionalCodeError = () => {
  return promotionalCodeError;
}

validation.addField(promotionalCodeField, [
  {
    validator: (code) => () => {
      return new Promise((resolve) => {
        if (code.length <= 0) {
          resolve(true);
          return;
        }
        const validatePromotionalCodeReadyUrl = validatePromotionalCodeUrl
          .replace('{code}', code)
          .replace('{orderNumber}', orderNumber);
        fetch(validatePromotionalCodeReadyUrl)
          .then(response => {
            return response.json();
          })
          .then(validation => {
              if (validation.valid === false) {
                promotionalCodeError = validation.reason;
              }
              resolve(validation.valid);
          });
      });
    },
    errorMessage: getPromotionalCodeError,
  }
]);

function clickApplyButton(event) {
  // Deactivate form submission.
  event.preventDefault();
  // Manually trigger promotional code field validation.
  validation.revalidateField(promotionalCodeField).then(isValid => {
    // Do something more, eventually.
  });
}

The only workaround I found is to use directly validateField with afterInputChanged at false.
Like so :

validation.validateField(key, false).finally(() => {
  validation.clearFieldStyle(key);
  validation.clearFieldLabel(key);
  validation.renderFieldError(key, true);
});

Do I did something wrong, or is that wanted from revalidateField ?

I think that the revalidateField method should perform all validation unconditionally because it is checked at a specific point the developer wants.
In my case, I want to perform asynchronous validation when focusing out of a specific tag, but I have a validation problem with the same problem.
The correct code I think is:

  revalidateField(fieldSelector) {
    if (typeof fieldSelector !== "string" && !isElement(fieldSelector)) {
      throw Error(
        `Field selector is not valid. Please specify a string selector or a valid DOM element.`
      );
    }
    const key = this.getKeyByFieldSelector(fieldSelector);
    if (!key || !this.fields[key]) {
      console.error(`Field not found. Check the field selector.`);
      return Promise.reject();
    }
    return new Promise((resolve) => {
      // AS-IS
      // this.validateField(key, true).finally(() => {
      // TO-BE
      this.validateField(key, false).finally(() => {
        this.clearFieldStyle(key);
        this.clearFieldLabel(key);
        this.renderFieldError(key, true);
        resolve(!!this.fields[key].isValid);
      });
    });
  }