Using Oracle JET Validators

Oracle JET validators provide properties that allow callers to customize the validator instance. The properties are documented as part of the validators’ API. Unlike converters where only one instance of a converter can be set on a component, page authors can associate one or more validators with a component.

When a user interacts with the component to change its value, the validators associated with the component are run in order. When the value violates a validation rule, the value option is not populated, and the validator highlights the component with an error.

You can use the validators with an Oracle JET component or instantiate and use them directly on the page.

Topics:

Using Oracle JET Validators with Oracle JET components

Oracle JET editable components, such as ojInputText and ojInputDate, set up validators both implicitly, based on certain options they support such as required, min, max, and so on, and explicitly by providing a means to set up one or more validators using the component's validators option. As with the Oracle JET converters, the validators property can be specified either using JSON array notation or can be an array of actual validator instances.

For example, the following code sample shows a portion of a form containing an ojInputDate component that uses the default validator supplied by the component implicitly. The highlighted code shows the HTML5 attribute set on the input element and the binding for the ojInputDate component. When the ojInputDate component reads the min attribute, it creates the implicit oj.DateTimeRangeValidator.

<div id="validator-example" class="oj-form oj-md-odd-cols-4 oj-md-labels-inline oj-sm-odd-cols-12">
  <div class="oj-flex">
    <div class="oj-flex-item">
      <label for="dateTimeRange1">'min' attribute and 'max' option</label>
    </div>
    <div class="oj-flex-item">
      <input id="dateTimeRange1" type="date" name="dateTimeRange1"
             min="2000-01-01T08:00:00.000"
             title="enter a date that falls in the current millenium and not greater than today's date."
             data-bind="ojComponent:{component:'ojInputDate', value: dateValue1, max: todayIsoDate}"/>
    </div>
  </div>
</div>

The script to create the view model for this example is shown below.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojinputnumber', 'ojs/ojinputtext', 'ojs/ojdatetimepicker', 'ojs/ojvalidation-datetime'],
function(oj, ko, $)
{
  function DemoViewModel()
  {
    var self = this;
    self.dateValue1 = ko.observable();
    self.dateValue2 = ko.observable();
    self.todayIsoDate =
      ko.observable(oj.IntlConverterUtils.dateToLocalIso(new Date()));
    self.milleniumStartIsoDate = ko.observable(oj.IntlConverterUtils.dateToLocalIso(new Date(2000, 00, 01)));
  };
 
  $(
    function()
    {
      ko.applyBindings(new DemoViewModel(), document.getElementById('validator-example'));     
    }
  );
});
 

When the user runs the page, the ojInputDate component displays an input field with the expected date format. When the user clicks on the field, the validator hint provided by the implicitly created oj.DateTimeRangeValidator, along with the title attribute set on the element, are shown in the note window. If the user inputs data that is not within the expected range, the built-in validator displays an error message with the expected range.

The error thrown by the Oracle JET validator when validation fails is represented by the oj.ValidatorError object, and the error message is represented by the oj.Message object. The messages and hints that Oracle JET validators use when they throw an error are resources that are defined in the translation bundle included with Oracle JET. For more information about messaging in Oracle JET, see Working with User Assistance.

You can also specify the validator directly on the component's validators property, if it exists. The code sample below adds another ojInputDate component to the sample form and specifies the oj.DateTimeRangeValidator validator (dateTimeRange) in the validators property with options that set the valid minimum and maximum dates and a hint that displays when the user sets the focus in the field.

<div class="oj-flex">
  <div class="oj-flex-item">
    <label for="dateTimeRange2">'dateTimeRange' type in 'validators' option</label>
  </div>
  <div class="oj-flex-item">
    <input id="dateTimeRange2" type="date" name="dateTimeRange2"
      title="enter a date in your preferred format and we will attempt to figure it out"
      data-bind="ojComponent:{component:'ojInputDate', value: dateValue2,
        validators: [{type: 'dateTimeRange', options: {
          max: todayIsoDate,
          min: milleniumStartIsoDate,
          hint: {'inRange': 'Enter a date that falls in the current millennium.'}}}]}"/>
  </div>
</div>

The highlighted code below shows the additions to the viewModel.

require(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojknockout', 'ojs/ojinputnumber', 'ojs/ojinputtext', 'ojs/ojdatetimepicker', 'ojs/ojvalidation-datetime'],
function(oj, ko, $)
{
  function DemoViewModel()
  {
    var self = this;
    self.dateValue1 = ko.observable();
    self.dateValue2 = ko.observable();
    self.todayIsoDate =
      ko.observable(oj.IntlConverterUtils.dateToLocalIso(new Date()));
    self.milleniumStartIsoDate =
      ko.observable(oj.IntlConverterUtils.dateToLocalIso(new Date(2000, 00, 01)));
  };
 
  $(
    function()
    {
      ko.applyBindings(new DemoViewModel(), document.getElementById('validator example'));     
    }
  );
});
 

When the user runs the page for the en-US locale, the ojInputDate component displays an input field that expects the user's input date to be between 01/01/00 and the current date. When entering a date value into the field, the date converter will accept alternate input as long as it can parse it unambiguously. This offers end users a great deal of leniency when entering date values.

For example, typing 1-2-3 will convert to a Date that falls on the 2nd day of January, 2003. If the Date value also happens to fall in the expected Date range set in the validator, then the value is accepted. If validation fails, the component will display an error.

The options that each validator accepts are specified in JavaScript API Reference for Oracle® JavaScript Extension Toolkit (JET).

The Oracle JET Cookbook contains the complete example used in this section as well as examples that show the built-in validators for date restrictions, length, number range, regular expression, and required fields. For details, see Validators.

For more information about Oracle JET component validation, see Understanding How Validation and Messaging Works in Oracle JET Editable Components.

Using Custom Validators in Oracle JET

You can create custom validators in Oracle JET by extending oj.Validator or by duck typing it. You can also create a custom validator factory to register the validator with Oracle JET and make it easier to instantiate the validator by name.

For example, the following code creates an instance of customValidator.

oj.Validation.validatorFactory('customValidator').createValidator();

Custom validators can be used with Oracle JET components, provided they don't violate the integrity of the component. As with the built-in Oracle JET validators, you can also use them directly on the page. For information about messaging in Oracle JET, see Using the messagesCustom Option.

The figure below shows an example of a custom validator used to validate password entries. If the user's password doesn't match, the validator displays an error message.

To create and use a custom validator in Oracle JET:

  1. Define the custom validator.

    The highlighted code in the sample below shows the definition for the equalToPassword custom validator used in the figure above. The validator duck types the oj.Validator contract. Because the validator provides the methods expected of a validator, the Oracle JET framework accepts it.

    function DemoViewModel ()
    {
      var self = this;
      self.password = ko.observable();
      self.passwordRepeat = ko.observable();
    
      // When password observable changes, validate the Confirm Password component
      // if it holds a non-empty value.
      self.password.subscribe (function (newValue)
      {
        var $cPassword = $("#cpassword"), cpUIVal = $cPassword.val();
        if (newValue && cpUIVal)
        {
          $cPassword.ojInputPassword("validate");
        }
      });
    
      // A validator associated to the Confirm Password field, that compares
      // the value in the password observable matches the value entered in the
      // Confirm Password field.
    
      self.equalToPassword = {
    
        validate: function(value)
        {
          var compareTo = self.password.peek();
          if (!value && !compareTo)
            return true;
          else if (value !== compareTo)
          {
            throw new Error(bundle['app']['validator-equalTo']['summary']);
          }
          return true;
        }
      };
    }
    ko.applyBindings(new DemoViewModel(), document.getElementById('custom-validator-example'));
    
  2. Optionally, create a validator factory for the custom validator that supports a createValidator() method, meeting the contract defined by oj.ValidatorFactory.

    The following code sample shows a simple validator factory for the equalToPassword validator. The code also registers the factory with Oracle JET as a new equalToPassword type using the oj.Validation module.

    /**
     * A validator factory for "equalTo" that validates two input values are equal.
     *
     * @return {{createValidator: function((Object|null)): (Object|null)}}
     * @class
     * @public
     */
    equalToPasswordValidatorFactory = (function () {
      /**
      * Private function that takes regular and relative options.
      *
      * @param {Object} options
      * @return {Object}
      * @private
      */
      function _createEqualToPasswordValidator(options)
      {
        return new equalToPasswordValidator (options);
      }
     
      return {
        'createValidator': function (options) {
          return _createEqualToPasswordValidator (options);
        }
      };
    }());
     
    /** Register the  factory with JET */
    oj.Validation.validatorFactory("equalToPassword", // factory name
                                    equalToPasswordValidatorFactory);
    
    
  3. Add code to your application that uses the custom validator.

    The code sample below shows how you could add code to your page to use the custom validator. In this example, both input fields are defined as ojInputPassword components. The first ojInputPassword component uses oj.RegExpValidator to validate that the user has input a password that meets the application's password requirements. The second ojInputPassword component uses the equalToPassword validator to verify that the password in the second field is equal to the password entered in the first field.

    <div id="custom-validator-example" class="oj-form oj-md-odd-cols-4 oj-md-labels-inline">
      <div class="oj-flex"> 
        <div class="oj-flex-item">
          <label for="password">Password</label>
        </div>
        <div class="oj-flex-item">
     
        <input id="password" type="password" name="password" required
          title="Enter at least 6 characters including a number, one uppercase and lowercase letter"
          data-bind="ojComponent: {component: 'ojInputPassword', value: password,
            invalidComponentTracker: invalidComponents,
            validators: [{type: 'regExp', options : {pattern: '(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{6,}',
            label: 'Password', messageSummary : '\'{label}\' too Weak',
            messageDetail: 'You must enter a password that meets our minimum
              security requirements.'}}]}"/>
       <div class="oj-flex">
        <div class="oj-flex-item">
          <label for="cpassword">Confirm Password</label>
        </div>
        <div class="oj-flex-item">
          <input id="cpassword" type="password" name="cpassword"
            data-bind="ojComponent: {component: 'ojInputPassword', instance: passwordRepeat,
            validators: [equalToPassword]}"/>
        </div>
      </div>
    </div>
    
    

    For the complete code sample used in this section, see Validators (Custom).

Using Oracle JET Validators Without an Oracle JET Component

If you want to use the validator without binding it to an Oracle JET component, create the validator using the oj.Validation.validatorFactory.createValidator() method.

For example, the following code creates the number range validator:

oj.Validation.validatorFactory(oj.ValidatorFactory.VALIDATOR_TYPE_NUMBERRANGE).createValidator();