Link Search Menu Expand Document

Custom validations

We’ve built a powerful API that allows you to hook into our forms’ validation system. Here’s how you add a custom validation to one of our forms:

// Wait until the form has initialized (it emits a 'cf:ready' event, and this function waits for that event)
CF.ready(function() {
  var validation = {
    comparator: function isValid(fieldValue) {
      // if fieldValue is valid:
      return true;

      // if fieldValue is NOT valid:
      return false;
    },

    // Display this error message if the comparator does not return true
    errorMessage: 'Field value is not valid',

    // If your comparator is asynchronous (if it returns a Promise,) set this to true. 
    // Otherwise, you don't need it. More on this below!
    async: false,
  };

  var $form = document.querySelector('form[data-cf-form]');

  // Add this validation to all fields with a data column key of "first_name"
  $form.cfForm.addValidator(validation, 'first_name');
});

It’s important that you wait for the cf:ready event before calling cfForm.addValidator, because that functionality won’t be available until that event is fired. Using our handy CF.ready function will do that for you!

Comparators

A comparator is a function that determines whether or not a fieldValue is valid by returning true or false. There are two types of comparators you can implement:

  • Synchronous

Synchronous comparators run instantaneous logic to determine whether or not a field value is valid. Use-cases for this involve sanitizing data and ensuring it is in the correct format.

Here’s an example that ensures the field value is an even number:

function isEven(fieldValue) {
  return fieldValue % 2 == 0;
}
  • Asynchronous

Asynchronous comparators can perform operations that are not instantaneous. Use-cases include: API requests, something that involves setTimeout or setInterval or anything else of that nature. This is accomplished by returning a Promise in your comparator that resolves a boolean, true if valid and false otherwise. Check out this example comparator that uses fetch to make an API request:

function isVerifiedByThirdPartyService(fieldValue) {
  return new Promise(function(resolve, reject) {
    fetch('https://some-service.com/verify?value=' + fieldValue)
      .then(function(response) {
        // If your service returns a JSON object in the response, you'll need to parse it:
        return response.json();
      })
      .then(function(responseBody) {
        if (responseBody.someData) {
          // Field is valid.
          resolve(true); 
        } else {
          // Field is invalid.
          resolve(false);
        }
      })
      .catch(function(error) {
        // Request failed. Probably some internal problem with the server.
        // You should resolve(true) so that a broken service doesn't interfere
        // with your form's submissions.
        console.error('Bad response from server:', error);
        resolve(true);
      });
  });
}

Don’t worry, both fetch and Promise are polyfilled!

Note

If you’re using an asynchronous comparator, make sure your validation has the async: true flag!

There are multiple benefits from using this:

  • They don’t run unless all sychronous validations have passed, ensuring valid, safe data is sent to your service(s)
  • Synchronous validations won’t be affected. Without the async: true flag, they will not show until all async validations have been evaluated, which can take seconds at a time
  • The field will display a spinner while validating, informing your customers that it’s waiting on something

Next up: Guides


Have any questions or comments about this post? Let us know! Your feedback is greatly appreciated.

Customer Fields is a Shopify app made by Helium.

Copyright © 2020 Helium Development, LLC