Pristine icon indicating copy to clipboard operation
Pristine copied to clipboard

Custom Validator with Promise / XHR Requests ("Timeouts") are not working / always false

Open Maybach91 opened this issue 3 years ago • 6 comments

Hej,

i try to check the input against an API / XHR Request and output the error according to the response as true or false.

I’ve tried it with a simple Timeout within one of the demos: https://codepen.io/Maybach/pen/mdEQjWN

When you remove the setTimeout on line 12, then it works. The timeout simulates my XHR request (which takes time / is a Promise).

What i’m trying to do: Only when the input is valid (an e-mail), then send the XHR request. XHR Request response with a 200 or 409. If 200, the input is valid / free username. If 409 the e-mail is already registered and want to tell this the user.

pristine.addValidator(
    emailField,
    function (value) {
      if (!this.validity.typeMismatch) { // Check if HTML5 says its a valid input → maybe do this with Pristine as well
        makeRequest({
          method: "GET",
          url:
            "REQUESTURL?username=" +
            value
        })
          .then(function (data) {
            return true;
          })
          .catch(function (err) {
            console.log(err);
            return false;
          });
      }
      return false;
    },
    "E-Mail already registered, want to Login?",
    2,
    true
  );

(makeRequest is just a simple XHR Request which returns a Promise → this works)

Maybach91 avatar Nov 11 '20 08:11 Maybach91

since its a async function aka timeout/promise it should be used as such. (sorry i’m new to promises haha)

But its still not working. I never geht the error shown.

pristine.addValidator(
    emailField,
    async function (value) {
      let success;
      if (!this.validity.typeMismatch) { // Check if HTML5 says its a valid input → maybe do this with Pristine as well
        try {
          success = await makeRequest({
          method: "GET",
          url:
            "REQUESTURL?username=" +
            value
          });
         }
         catch {
            success = false;
         } 
      }
      return success; // Waits till makeRquest is resolved and return the value (true/false) ← THIS IS NOT WORKING 
    },
    "E-Mail already registered, want to Login?",
    2,
    true
  );

Maybach91 avatar Nov 11 '20 16:11 Maybach91

Facing the same issue, watching closely!

rickvdbroek avatar Nov 17 '20 11:11 rickvdbroek

Adding an error in a promise is not working too. I built a working to add my error and it works, but when an error is added within a promise, the pristine.validate() returns true.

image but there are the errors in the fields within the pristine object

Maybach91 avatar Nov 17 '20 19:11 Maybach91

Almost a year later and I'm facing the same issue. @Maybach91 just wondering did you ever figure out a work around?

Nevario avatar Oct 29 '21 03:10 Nevario

Almost a year later and I'm facing the same issue. @Maybach91 just wondering did you ever figure out a work around?

@Nevario Looking at my own 1 year old code, i can only give it to you, but cannot explain all the reasons behind this anymore. But maybe it helps. Basically i swap the logic and handling errors within the Promise instead of use the built in async validation of pristine.addValidator.

// ------------------
  // E-Mail API Request
  // ------------------
  // Checks if the EMAIL is already registered on the API endpoint
  
  const debug = true; // logs everything whats happening
  const checkUsernameApiUrl = 'YOUR_API_URL'; // your api url to check the form data against to
  const loginUrl = 'LOGIN_URL'; // url to the login page. if email is already registered it shows a hint to directly login instead
  
  // Init a timeout variable to be used for email check
  let timeout = null;

  const checkEmailExistence = (email) => {
    const fieldParent = emailField.parentNode;
    return new Promise(function (resolve, reject) {
      // Clear the timeout if it has already been set.
      // This will prevent the previous task from executing
      // if it has been less than <MILLISECONDS>
      clearTimeout(timeout);

      // Make a new timeout set to go off in 1000ms (1 second)
      timeout = setTimeout(function () {

        makeRequest({
          method: "GET",
          url: checkUsernameApiUrl + encodeURIComponent(email)
        }).then(response => {
          if (response.length) {
            debug &&
            console.info(
              `%c ${email} is available`,
              "color: #009d55; background-color:#c4eac1"
            );
            fieldParent.classList.remove('is-loading');
            fieldParent.classList.add('is-successful');

            setTimeout(function () {
              fieldParent.classList.remove('is-successful');
            }, 2000);

            resolve(true);
          } else {
            debug &&
            console.error(`%c ${email} is not available`, "color: #d60202");

            pristine.addError(
              emailField,
              `E-Mail already registered, <a target="_blank" href="${loginUrl}">Login</a>?`
            );

            fieldParent.classList.remove('is-loading');
            reject(false);

          }
        }).catch((err) => {

          if (err.status === 409) {
            debug && console.error(`%c ${email} is not available`, "color: #d60202");
            pristine.addError(
              emailField,
              `E-Mail already registered, <a target="_blank" href="${loginUrl}">Login</a>?`
            );

            fieldParent.classList.remove('is-loading');
            reject(false);
          } else {
            if (debug) {
              console.group("Server Error");
              console.info(
                "Server not reachable, blocked because of CORS policy, try setting a proxy?"
              );
              console.error(err);
              console.groupEnd();
            }

            fieldParent.classList.remove('is-loading');
            reject(err);
            throw new Error(
              "Server not reachable, blocked because of CORS policy, try setting a proxy?",
              err
            );
          }
        });
      }, 400);
    });
  }

Maybach91 avatar Nov 02 '21 10:11 Maybach91

@Maybach91 Thank-you very much. This was incredibly helpful in getting me to a solution!

Nevario avatar Nov 06 '21 21:11 Nevario