10 Validate and Convert Input

Oracle JET includes validators and converters on a number of Oracle JET editable elements, including oj-combobox, oj-input*, and oj-text-area. You can use them as is or customize them for validating and converting input in your Oracle JET app.

Some editable elements such as oj-checkboxset, oj-radioset, and oj-select have a simple attribute for required values that implicitly creates a built-in validator.

Note:

The oj-input* mentioned above refers to the family of input components such as oj-input-date-time, oj-input-text, and oj-input-password, among others.

About Oracle JET Validators and Converters

Oracle JET provides converter classes that convert user input strings into the data type expected by the app and validator classes that enforce a validation rule on those input strings.

For example, you can use Oracle JET's IntlDateTimeConverter to convert a user-entered date to a Date object for use by the app's ViewModel and then use DateTimeRangeValidator to validate that input against a specified time range. You can also use converters to convert Date or Number objects to a string suitable for display or convert color object formats.

To retrieve the converter or validator factory for a registered type, Oracle JET provides the Validation class which includes methods to register and retrieve converter and validator factories.

If the converters or validators included in Oracle JET are not sufficient for your app, you can create custom converters or validators. Optionally, you can provide a custom factory that implements the contract for a converter using ConverterFactory or a validator using ValidatorFactory and register the converter or validator with the Validation class. The Validation class enables you to access your custom converter or validator using the same mechanisms as you would use with the Oracle JET standard converters and validators.

About Validators

All Oracle JET editable elements support a value attribute and provide UI elements that allow the user to enter or choose a value. These elements also support other attributes that page authors can set that instruct the element how it should validate its value.

An editable element may implicitly create a built-in converter and/or built-in validators for its normal functioning when certain attributes are set.

For example, editable elements that support a required property create the required validator implicitly when the property is set to true. Other elements like oj-input-date, oj-input-date-time, and oj-input-time create a datetime converter to implement its basic functionality.

About the Oracle JET Validators

The following table describes the Oracle JET validators and provides links to the API documentation:

Validator Description Link to API Module

DateTimeRangeValidator

Validates that the input date is between two dates, between two times, or within two date and time ranges

DateTimeRangeValidator

ojvalidation-datetimerange

DateRestrictionValidator

Validates that the input date is not a restricted date

DateRestrictionValidator

ojvalidation-daterestriction

LengthValidator

Validates that an input string is within a specified length

LengthValidator

ojvalidation-length

NumberRangeValidator

Validates that an input number is within a specified range

NumberRangeValidator

ojvalidation-numberrange

RegExpValidator

Validates that the regular expression matches a specified pattern

RegExpValidator

ojvalidation-regexp

RequiredValidator

Validates that a required entry exists

RequiredValidator

ojvalidation-required

About Oracle JET Component Validation Attributes

The attributes that a component supports are part of its API, and the following validation specific attributes apply to most editable elements.

Element Attribute Description

converter

When specified, the converter instance is used over any internal converter the element might create. On elements such as oj-input-text, you may need to specify this attribute if the value must be processed to and from a number or a date value.

countBy

When specified on LengthValidator, countBy enables you to change the validator’s default counting behavior. By default, this property is set to codeUnit, which uses JavaScript's String length property to count a UTF-16 surrogate pair as length === 2. Set this to codePoint to count surrogate pairs as length ===1.

max

When specified on an Oracle JET element like oj-input-date or oj-input-number, the element creates an implicit range validator.

min

When specified on an Oracle JET element like oj-input-date or oj-input-number, the component creates an implicit range validator.

pattern

When specified on an Oracle JET element like oj-input-text, oj-input-password, or oj-text-area, the component creates an implicit regExp validator using the pattern specified. If the regular expression pattern requires a backslash, while specifying the expression within an Oracle JET element, you need to use double backslashes. For more information, see Use Oracle JET Validators with Oracle JET Components.

placeholder

When specified, it displays placeholder values in most elements.

required

When specified on an Oracle JET element, the element creates an implicit required validator.

validators

When specified, the element uses these validators along with the implicit validators to validate the UI value. Can be implemented with Validators or AsyncValidators to validate the user input on the server asynchronously.

Some editable elements do not support specific validation attributes as they might be irrelevant to its intrinsic functioning. For example, oj-radioset and oj-checkboxset do not support a converter attribute since there is nothing for the converter to convert. For an exact list of attributes and how to use them, refer to the Attributes section in the element’s API documentation. For Oracle JET API documentation, see API Reference for Oracle® JavaScript Extension Toolkit (Oracle JET). Select the component you're interested in viewing from the API list.

About Oracle JET Component Validation Methods

Oracle JET editable elements support the following methods for validation purposes. For details on how to call this method, its parameters and return values, refer to the component’s API documentation.

Element Method Description

refresh()

Use this method when the DOM the element relies on changes, such as the help attribute tooltip on an oj-label changing due to a change in locale.

reset()

Use this method to reset the element by clearing all messages and messages attributes - messagesCustom - and update the element’s display value using the attribute value. User entered values will be erased when this method is called.

validate()

Use this method to validate the component using the current display value.

For details on calling a element's method, parameters, and return values, See the Methods section of the element's API documentation in API Reference for Oracle® JavaScript Extension Toolkit (Oracle JET). You can also find detail on how to register a callback for or bind to the event and for information about what triggers the events. Select the component you're interested in viewing from the API list.

About Converters

The Oracle JET converters include date-time, number, and color converters and are described in the following table.

Converter Description Link to API

ColorConverter

Converts Color object formats

ColorConverter

IntlDateTimeConverter

Converts a string to a Date or a Date to a string

IntlDateTimeConverter

IntlNumberConverter

Converts a string to a number or formats a number or Number object value to a string

IntlNumberConverter

About Oracle JET Component Converter Options

Oracle JET Converters use the options attribute to allow a range of formatting options for color, number, and date and time values.

Color Converters

Color converters support the following options.

Option Name Description

format

Sets the format of the converted color specification. Allowed values are "rgb" (default), "hsl", "hsv" "hex", and "hex3" (3 digit hex code).

For an exact list of options and methods and how to use them, refer to API documentation of the ColorConverter class. See ColorConverter.

Number Converters

Number converters support a number of options that can be used to format decimal numbers, currency, percentages, or units. Some of the important options are:

Option Name Description

style

Sets the style of number formatting. Allowed values are "decimal" (default), "currency", "percent" or "unit".

For decimals, percentages, and units, the locale-appropriate symbols are used for decimal characters (point or comma) and grouping separators (if grouping is enabled).

currency

Mandatory when style is "currency". Specifies the currency that will be used when formatting the number. The value should be a ISO 4217 alphabetic currency code (such as USD or EUR).

currencyDisplay

Allowed values are "code", "name", and "symbol" (default). When style is currency, this option specifies if the currency is displayed as its name (such as Euro) an ISO 4217 alphabetic currency code (such as EUR), or the commonly recognized symbol (such as ).

unit

Mandatory when style is "unit". Allowed values are "byte" or "bit". This option is used for formatting only and cannot be used for parsing.

Use this option to format digital units like 10Mb for bit unit or 10MB for byte unit. Note that scale is formatted automatically. For example, 1024 (with the byte unit set) is interpreted as 1 KB.

minimumIntegerDigits

Sets the minimum number of digits before the decimal place. The number is padded with leading zeros if it would not otherwise have enough digits. Allowed values are any integer from 1 to 21.

minimumFractionDigits

Sets the minimum number of digits after the decimal place. The number is padded with trailing zeros if it would not otherwise have enough digits. Allowed values are any integer from 0 to 20.

maximumFractionDigits

Sets the maximum number of digits after the decimal place. The number is rounded if it has more than the set maximum number of digits. Allowed values are any integer from 0 to 20.

pattern

Sets a pattern to use for the number, overriding other options. The pattern uses the symbols specified in the Unicode CLDR for numbers, percent, and currency formats.

For the currency format, the currency option must be set. Use of the currency symbol (¤) indicates whether it will be displayed or not. For example, {pattern: '¤#,##0', currency: 'USD'}.

For the percentage format, if the style option is set to 'percent', use of the percentage symbol (%) indicates whether it will be displayed or not. If the style option is not set to percent, the percentage symbol is required. For example, {style: 'percent', pattern: "#,##0"}.

For the decimal or exponent patterns, the example is {pattern: "#,##0.00"} or {pattern: "0.##E+0"}.

roundingMode

Specifies the rounding behavior. Allowed values are HALF_UP, HALF_DOWN, and HALF_EVEN.

roundDuringParse

Specifies whether or not to round during parse. Defaults to false; the number converter rounds during format but not during parse.

For an exact list of options and methods and how to use them, refer to API documentation of the IntlNumberConverter class. See IntlNumberConverter.

For an example illustrating the use of Number Converter options, see Number Converter.

DateTime Converters

DateTime converters support a wide array of options that can be used to format date and time values in all common styles across locales. Some of the important options are:

Option Name Description

year

Allowed values are the strings "2–digit" (00–99) and "numeric" (full year value, default).

month

Allowed values are the strings "2–digit" (01–12), "numeric" (variable digit value such as 1 or 11, default), "narrow" (narrow name such as J for January), "short" (abbreviated name such as Jan), and "long" (wide name such as January).

day

Allowed values are the strings "2–digit" (01–31) and "numeric" (variable digit value such as 1 or 18, default).

formatType

Determines the standard date and/or time format lengths to use. Allowed values are "date", "time", "datetime". When set, a value for dateFormat or timeFormat must be specified where appropriate.

dateFormat

Specifies the standard date format length to use when formatType is set to "date" or "datetime". Allowed values are "short" (default), "medium", "long", "full".

timeFormat

Specifies the standard time format length to use when formatType is set to "time" or "datetime". Allowed values are "short" (default), "medium", "long", "full".

hour

Allowed values are the strings "2–digit" (01–12 or 01–24) and "numeric" (variable digit value such as 1 or 23).

minute

Allowed values are the strings "2–digit" and "numeric". This value is always displayed as 2 digits (00–59).

second

Allowed values are the strings "2–digit" and "numeric". This value is always displayed as 2 digits (00–59).

For an exact list of options and methods and how to use them, refer to API documentation of the IntlDateTimeConverter class. See IntlDateTimeConverter.

For an example illustrating the use of DateTime Converter options, see DateTime Converter.

About Oracle JET Converters

The Oracle JET color, date-time, and number converters, ColorConverter, IntlDateTimeConverter, and IntlNumberConverter, extend the Converter object which defines a basic contract for converter implementations.

The converter API is based on the ECMAScript Internationalization API specification (ECMA-402 Edition 1.0) and uses the Unicode Common Locale Data Repository (CLDR) for its locale data. Both converters are initialized through their constructors, which accept options defined by the API specification. For additional information about the ECMA-402 API specification, see https://www.ecma-international.org/publications-and-standards/standards/ecma-402/. For information about the Unicode CLDR, see http://cldr.unicode.org.

The Oracle JET implementation extends the ECMA-402 specification by introducing additional options, including an option for user-defined patterns. For the list of additional options, see the ColorConverter, IntlDateTimeConverter, and IntlNumberConverter API documentation.

For examples that illustrate the date-time and number converters in action, see the Converters section in the Oracle JET Cookbook. For examples using the color converter, see the Color Palette and Color Spectrum Cookbook samples.

Note:

The bundles that hold the locale symbols and data used by the Oracle JET converters are downloaded automatically based on the locale set on the page when using RequireJS and the ojs/ojvalidation-datetime or ojs/ojvalidation-number module. If your app does not use RequireJS, the locale data will not be downloaded automatically.

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

Use Oracle JET Converters with Oracle JET Components

Oracle JET elements that accept user input, such as oj-input-date, already include an implicit converter that is used when parsing user input. However, you can also specify an explicit converter on the element which will be used instead when converting data from the model for display on the page and vice versa. An explicit converter is required if you want to include time zone data.

For example, the following code sample shows a portion of a form containing an oj-input-date component that uses the default converter supplied by the component implicitly. The highlighted code shows the oj-input-date component.

<oj-form-layout id="datetime-converter-example">
  ... contents omitted
  <oj-input-date id="date1" value="{{date}}" name="date1"
                 label-hint="input date with no converter"
                 help.instruction="enter a date in your preferred format and we will attempt to figure it out">
  </oj-input-date>
</oj-form-layout>

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

require(['knockout', 'ojs/ojbootstrap', 'ojs/ojknockout', 'ojs/ojdatetimepicker', 'ojs/ojlabel'],
  function(ko, Bootstrap)
  {
    function MemberViewModel() 
    {
      var self = this;
      self.date = ko.observable();
      self.datetime = ko.observable();
      self.time = ko.observable();
    };

    Bootstrap.whenDocumentReady().then(
      function ()
      {
        ko.applyBindings(new MemberViewModel(), document.getElementById('datetime-converter-example'));      
      }
    );
  }); 

When the user runs the page, the oj-input-date element displays an input field with the expected date format. In this example, the element also displays a hint when the user hovers over the input field, and displays a calendar when the user clicks in the input field. If the user inputs data that is not in the expected format, the built-in converter displays an error message with the expected format.

The error that the converter throws when there are errors during parsing or formatting operations is represented by the ConverterError object, and the error message is represented by an object that duck-types Message. The messages that Oracle JET converters use are resources that are defined in the translation bundle included with Oracle JET. For more information about messaging in Oracle JET, see Work with User Assistance.

You can also specify the converter directly on the element's converter attribute, if it exists. The code excerpt below defines another oj-input-date element on the sample form and specifies the IntlDateTimeConverter converter with options that will convert the user's input to a numeric year, long month, and numeric day according to the conventions of the locale set on the page. The options parameter is an object literal that contains the ECMA-402 options as name-value pairs.

<div class="oj-flex">
  <div class="oj-flex-item">
    <oj-label for="date2">input date</oj-label>
  </div>
  <div class="oj-flex-item">
    <oj-input-date id="date2" value="{{date}}" name="date2"
                   help.instruction="enter a date in your preferred format and we will attempt to figure it out"
                   converter= '{
                     "type":"datetime",
                     "options": {"year": "numeric", "month": "long", "day": "numeric"}}'>
    </oj-input-date>
  </div>
</div>

When the user runs the page in the en-us locale, the oj-input-date element displays an input field that expects the user's input date to be in the mmmm d, yyyy format. The converter will accept alternate input if it makes sense, such as 18/07/17 (MM/dd/yy), and perform the conversion, but will throw an error if it cannot parse the input. For details about Oracle JET converters and lenient parsing support, see About Oracle JET Converters Lenient Parsing.

Parsing of narrow era, weekday, or month name is not supported because of ambiguity in choosing the right value. For example, if you initialize the date time converter with options {weekday: 'narrow', month: 'narrow', day: 'numeric', year: 'numeric'}, then for the en-US locale, the converter will format the date representing May 06, 2014 as T, M 6, 2014, where T represents Tuesday. If the user inputs T, M 6, 2014, the converter can't determine whether the user meant Thursday, March 6, 2014 or Tuesday, May 6, 2014. Therefore, Oracle JET expects that user input be provided in either their short or long forms, such as Tues, May 06, 2014.

For additional details about the IntlDateTimeConverter and IntlNumberConverter component options, see IntlDateTimeConverter and IntlNumberConverter.

About Oracle JET Converters Lenient Parsing

The Oracle JET converters support lenient number and date parsing when the user input does not exactly match the expected pattern. The parser does the lenient parsing based on the leniency rules for the specific converter.

IntlDateTimeConverter provides parser leniency when converting user input to a date and enables the user to:

  • Input any character as a separator irrespective of the separator specified in the associated pattern. For example, if the expected date pattern is set to y-M-d, the date converter will accept the following values as valid: 2020-06-16, 2013/06-16, and 2020aaa06xxx16. Similarly, if the expected time pattern is set to HH:mm:ss, the converter will accept the following values as valid: 12.05.35.

  • Specify a 4-digit year in any position relative to day and month. For example, both 11-2013-16 and 16-11-2013 are valid input values.

  • Swap month and day positions, as long as the date value is greater than 12 when working with the Gregorian calendar. For example, if the user enters 2020-16-06 when y-M-d is expected, the converter will autocorrect the date to 2020-06-16. However, if both date and month are less or equal to 12, no assumptions are made about the day or month, and the converter parses the value against the exact pattern.

  • Enter weekday and month names or mix short and long names anywhere in the string. For example, if the expected pattern is E, MMM, d, y, the user can enter any of the following dates:

    Tue, Jun 16 2020
    Jun, Tue 2020 16
    2020 Tue 16 Jun
    
  • Omit weekdays. For example, if the expected pattern is E, MMM d, y, then the user can enter Jun 16, 2020, and the converter autocorrects the date to Tuesday, Jun 16, 2020. Invalid weekdays are not supported. For instance, the converter will throw an exception if the user enters Wednesday, Jun 16, 2020.

IntlNumberConverter supports parser leniency as follows:

  • If the input does not match the expected pattern, Oracle JET attempts to locate a number pattern within the input string. For instance, if the pattern is #,##0.0, then the input string abc-123.45de will be parsed as -123.45.

  • For the currency style, the currency symbol can be omitted. Also, the negative sign can be used instead of a negative prefix and suffix. As an example, if the pattern option is specified as "\u00a4#,##0.00;(\u00a4#,##0.00)", then ($123), (123), and -123 will be parsed as -123.

  • When the style is percent, the percent sign can be omitted. For example, 5% and 5 will both be parsed as 0.05.

Understand Time Zone Support in Oracle JET

By default, the oj-input-date-time and oj-input-time elements and IntlDateTimeConverter support only local time zone input. You can add time zone support by including the ojs/ojtimezonedata module and creating a converter with the desired pattern.

Oracle JET supports time zone conversion and formatting using the following patterns:

Token Description Example

z, zz, zzz

Abbreviated time zone name, format support only

PDT, PST

zzzz

Full time zone name, format support only

Pacific Standard Time, Pacific Daylight Time

Z, ZZ, ZZZ

Sign hour minutes

-0800

X

Sign hours

-08

XX

Sign hours minutes

-0800

XXX

Sign hours:minutes

-08:00

VV

Time Zone ID

America/Los Angeles

The image below shows the basic oj-input-date-time element configured for time zone support. In this example, the component is converted using the Z pattern.

The oj-input-date-time element is initialized with its converter attribute, in this case a method named dateTimeConverter.

<div id="div1">
  <oj-label for="timezone">InputDateTime Timezone converter</oj-label>
  <oj-input-date-time id="timezone" value={{dateTimeValue}} converter=[[dateTimeConverter]]>
  </oj-input-date-time>
  <br/><br/>
  <p>
  <oj-label for="patternSelector">Pattern options:</oj-label>
  <oj-combobox-one id="patternSelector" value="{{patternValue}}">
    <oj-option value="MM/dd/yy hh:mm:ss a Z">MM/dd/yy hh:mm:ss a Z</oj-option>
    <oj-option value="MM-dd-yy hh:mm:ss a VV">MM-dd-yy hh:mm:ss a VV</oj-option>
    <oj-option value="MM-dd-yy hh:mm X">MM-dd-yy hh:mm X</oj-option>
  </oj-combobox-one>
  </p>
  <p>
  <oj-label for="isoStrFormatSelector">isoStrFormat options:</oj-label>
    <oj-combobox-one id="isoStrFormatSelector" value="{{isoStrFormatValue}}">
      <oj-option value="offset">offset</oj-option>
      <oj-option value="zulu">zulu</oj-option>
      <oj-option value="local">local</oj-option>
    </oj-combobox-one>
  </p>
  <br/>
  <span class="oj-label">Current dateTime value is: </span>
  <span><oj-bind-text value="[[dateTimeValue]]"></oj-bind-text></span>
  //...contents omitted
</div>

The ViewModel contains the dateTimeConverter() definition. Note that you must also add the ojs/ojconverter-datetime module to use its DateTimeConverter API and add the ojs/timezonedata module to your RequireJS definition to access the time zone data files.

require(['knockout', 'ojs/ojbootstrap',
         'ojs/ojconverter-datetime', 'ojs/ojknockout',
         'ojs/ojdatetimepicker', 'ojs/ojselectcombobox',
         'ojs/ojtimezonedata', 'ojs/ojlabel'],   
    function (ko, Bootstrap, DateTimeConverter,)
    {
      function FormatModel()
      {
        var self = this;

        this.dateTimeValue = ko.observable("2020-06-16T20:00:00-08:00");
        this.patternValue = ko.observable("MM/dd/yy hh:mm:ss a Z");
        this.isoStrFormatValue = ko.observable("offset");
        this.dateTimeConverter = ko.observable(
          new DateTimeConverter.IntlDateTimeConverter(
          {
            pattern : self.patternValue(),
            isoStrFormat: self.isoStrFormatValue(),
            timeZone:'Etc/GMT-08:00'
          }));

        //Note that ojCombobox's value is always encapsulated in an array
        this.patternValue.subscribe(function (newValue) {
         this.dateTimeConverter
          new DateTimeConverter.IntlDateTimeConverter(
          {
            pattern : newValue,
            isoStrFormat: self.isoStrFormatValue(),
            timeZone:'Etc/GMT-08:00'
          }));
        }.bind(this));

        this.isoStrFormatValue.subscribe(function (newValue) {
         this.dateTimeConverter(
          new DateTimeConverter.IntlDateTimeConverter(
          {
            pattern : self.patternValue(),
            isoStrFormat: newValue,
            timeZone:'Etc/GMT-08:00'
          }));
        }.bind(this));
      
	//...contents omitted
      Bootstrap.whenDocumentReady().then(
        function ()
        {
          ko.applyBindings(new FormatModel(), document.getElementById('div1'));
        }
      );
    });

For an additional example illustrating how to add time zone support to oj-input-date-time and oj-input-time elements, see Input Date and Time - Time Zone.

Use Custom Converters in Oracle JET

You can create custom converters in Oracle JET by extending Converter or by duck typing it. You can also create a custom converter factory to register the converter with Oracle JET and make it easier to instantiate the converter.

Custom converters can be used with Oracle JET components, provided they don't violate the integrity of the component. As with the built-in Oracle JET converters, you can also use them directly on the page.

The figure below shows an example of a custom converter used to convert the current date to a relative term. The Schedule For column uses a RelativeDateTimeConverter to convert the date that the page is run in the en-US locale to display Today, Tomorrow, and the date in two days.

To create and use a custom converter in Oracle JET:

  1. Define the custom converter.

    The code sample below shows a portion of the RelativeDateTimeConverter definition. The converter wraps the Oracle JET IntlDateTimeConverter by providing a specialized format() method that turns dates close to the current date into relative terms for display. For example, in the en-US locale, the relative terms will display Today, Yesterday, and Tomorrow. If a relative notation for the date value does not exist, then the date is formatted using the regular Oracle JET format() method supported by the Oracle JET IntlDateTimeConverter.

    require(['knockout', 'ojs/ojbootstrap', 'ojs/ojconverter-datetime,
             'ojs/ojarraydataprovider', 'ojs/ojconverterutils-i18n', 
             'ojs/ojknockout', 'ojs/ojtable', 'ojs/ojbutton'],
        function (ko, Bootstrap, DateTimeConverter, ArrayDataProvider, ConvertI18nUtils)
        {
          ...contents omitted
          function RelativeDateTimeConverter(options) {
            this.Init(options);
          };
    
          // Defines default option values
          RelativeDateTimeConverter._DEFAULT_RELATIVE_DATETIME_CONVERTER_OPTIONS =
          {
            'formatUsing' : "displayName",
            'dateField' : "week"
          };
    
          // Initializes converter instance with the set options
          RelativeDateTimeConverter.prototype.Init = function(options)
          {
            this._options = options;
            //create datetime converter and use this as the wrapper converter.
            this._wrappedConverter = new DateTimeConverter.IntlDateTimeConverter(options);
          };
    
          // Returns the options set on the converter instance
          RelativeDateTimeConverter.prototype.getOptions = function ()
          {
            return this._options;
          };
    
          // Does not support parsing
          RelativeDateTimeConverter.prototype.parse = function(value)
          {
            return null;
          };
    
          // Formats a value using the relative format options. Returns the formatted
          // value and a title that is the actual date, if formatted value is a relative date.
          RelativeDateTimeConverter.prototype.format = function(value)
          {
            var base;
            var formattedRelativeDate;
    
            // We get our wrapped converter and call its formatRelative function and store the
            // return value ("Today", "Tomorrow" or null) in formatted variable
            // See IntlDateTimeConverter#formatRelative(value, relativeOptions)
            // where relativeOptions has formatUsing and dateField options. dateField is
            // 'day', 'week', 'month', or 'year'.
            formattedRelativeDate = this._getWrapped().formatRelative(value, this._getRelativeOptions());
            
            // We get our wrapped converter and call its format function and store the returned
            // string in base variable. This will be the actual date, not a relative date.
            base = this._getWrapped().format(value);
    
            // Capitalize the first letter of the string
            if (formattedRelativedate &amp;&amp; typeof formattedRelativeDate === "string")
            {
              formattedRelativeDate = formattedRelativeDate.replace(/(\w)(\w*)/g,
              function (match, i, r) {
                return i.toUpperCase() + (r !== null ? r : "");
              });
            }
            return {value: formatted || base, title: formattedRelativeDate ? base : ""}
           };
    
           // Returns a hint
           RelativeDateTimeConverter.prototype.getHint = function ()
           {
             return null;
           };
    
           RelativeDateTimeConverter.prototype._getWrapped = function ()
           {
             return this._wrappedConverter;
           };
    
           RelativeDateTimeConverter.prototype._getRelativeOptions = function ()
           {
             var options = this._options;
             var relativeOptions = {};
    
             if (options &amp;&amp; options["relativeField"])
             {
               relativeOptions['formatUsing'] = "displayName";
               relativeOptions['dateField'] = options["relativeField"];
             }
             else
             {
               relativeOptions = RelativeDateTimeConverter._DEFAULT_RELATIVE_DATETIME_CONVERTER_OPTIONS;
             }
    
             return relativeOptions;
           };
           ... contents omitted
    });

    The custom converter relies on the IntlDateTimeConverter converter's formatRelative() method. For additional details about the IntlDateTimeConverter converter's supported methods, see the IntlDateTimeConverter API documentation.

  2. Add code to your app that uses the custom converter.

    The code sample below shows how you could add code to your script to use the custom converter.

    var relativeDayOptions = {relativeField: 'day', year: "numeric",
                              month: "numeric", day: "numeric"};
    var rdConverter = new RelativeDateTimeConverter(relativeDayOptions);
    
  3. Add the Oracle JET element or elements that will use the custom converter to your page.

    For the code sample that creates the oj-table element and displays the Schedule For column in relative dates, see Converters (Custom).

Use Oracle JET Converters Without Oracle JET Components

If you want to use a converter without binding it to an Oracle JET component, create the converter using the constructor for the converter of your choice.

The Oracle JET Cookbook includes the Converters Factory demo that shows how to use the number and date time converters directly in your pages without binding them to an Oracle JET component. In the demo image, the salary is a number formatted as currency, and the start date is an ISO string formatted as a date.

The sample code below shows a portion of the viewModel that defines a salaryConverter to format a number as currency and a dateConverter that formats the start date using the date format style and medium date format.

require(['knockout', 'ojs/ojbootstrap, 'ojs/ojconverter-number', 
         'ojs/ojconverter-datetime', 'ojs/ojknockout',],
    function(ko, Bootstrap, NumberConverter, DateTimeConverter)
    {    
      function DemoViewModel() 
      {
        var self = this;
        // for salary fields
        var salOptions = {style: 'currency', currency: 'USD'};
        var salaryConverter = new NumberConverter.IntlNumberConverter(salOptions);

        self.amySalary = ko.observable(salaryConverter.format(125475.00));
        self.garySalary = ko.observable(salaryConverter.format(110325.25));

        // for date fields
        var dateOptions = {formatStyle: 'date', dateFormat: 'medium'};
        var dateConverter = new DateTimeConverter.IntlDateTimeConverter(dateOptions);
        
        self.amyStartDate = ko.observable(dateConverter.format("2020-01-02"));
        self.garyStartDate = ko.observable(dateConverter.format("2009-07-25"));
        ... contents omitted
});  

The code sample below shows the portion of the markup that sets the display output to the formatted values contained in amySalary, amyStartDate, garySalary, garyStartDate.

<td>
  <div class="oj-panel oj-panel-alt4 demo-panel-customizations">
    <h3 class="oj-header-border">Amy Flanagan</h3>
    <img src="images/Amy.png" alt="Amy">
    <p>Product Manager</p>
    <span style="white-space:nowrap;"><b>Salary</b>:
      <span>
        <oj-bind-text value="[[amySalary]]"></oj-bind-text>
      </span>
    </span>
    <br />
    <span style="white-space:nowrap;"><b>Joined</b>:
      <span>
        <oj-bind-text value="[[amyStartDate]]"></oj-bind-text>
      </span>
    </span>
    <br />
  </div>
</td>
<td>
  <div class="oj-panel oj-panel-alt2 demo-panel-customizations">
    <h3 class="oj-header-border">Gary Fontaine</h3>
    <img src="images/Gary.png" alt="Gary">
    <p>Sales Associate</p>
    <span style="white-space:nowrap;"><b>Salary</b>:
      <span>
        <oj-bind-text value="[[garySalary]]"></oj-bind-text>
      </span>
    </span>
    <br />
    <span style="white-space:nowrap;"><b>Joined</b>:
      <span>
        <oj-bind-text value="[[garyStartDate]]"></oj-bind-text>
      </span>
    </span>
    <br />
  </div>
</td>

About 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 an element, page authors can associate one or more validators with an element.

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

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

Use Oracle JET Validators with Oracle JET Components

Oracle JET editable elements, such as oj-input-text and oj-input-date, set up validators both implicitly, based on certain attributes 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 attribute. As with the Oracle JET converters, the validators attribute 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 oj-input-date element that uses the default validator supplied by the component implicitly. The highlighted code shows the HTML5 attribute set on the oj-input-date element. When the oj-input-date reads the min attribute, it creates the implicit DateTimeRangeValidator.

<oj-form-layout id="validator-example" label-edge="inside">
  <oj-input-date id="dateTimeRange1" value="{{dateValue1}}" min="2000-01-01T08:00:00.000"
                 help.instruction="Enter a date that falls in the current millenium and not greater than today's date."
                 max= '[[todayIsoDate]]' label-hint="'min' attribute and 'max' option">
  </oj-input-date>
</oj-form-layout>

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

require(['knockout', 'ojs/ojbootstrap', 'ojs/ojconverterutils-i18n',
          'ojs/ojasyncvalidator-datetimerange', 'ojs/ojconverter-datetime',
          'ojs/ojknockout', 'ojs/ojinputnumber', 'ojs/ojinputtext', 
          'ojs/ojdatetimepicker', 'ojs/ojlabel', 'ojs/ojformlayout'],
    function(ko, Bootstrap, ConverterUtilsI18n, AsyncDateTimeRangeValidator, DateTimeConverter)
    {
      function DemoViewModel() 
      {
        var self = this;
        self.dateValue1 = ko.observable();
        self.todayIsoDate = ko.observable(ConverterUtilsI18n.IntlConverterUtils.dateToLocalIso(new Date()));
      };

      Bootstrap.whenDocumentReady().then(
        function ()
        {
          ko.applyBindings(new DemoViewModel(), document.getElementById('validator-example'));      
        }
      );
    }); 

When the user runs the page, the oj-input-date element displays an input field with the expected date format. The help.instruction attribute set on the element displays as a tooltip upon hovering. When the user clicks on the field, the validator hint provided by the implicitly created DateTimeRangeValidator is shown in a note window, along with a calendar popup. 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 ValidatorError object, and the error message is represented by an object that duck-types Message. 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 Work with User Assistance.

You can also specify the validator on the element's validators attribute, if it exists. The code sample below adds another oj-input-date element to the sample form and calls a function which specifies the DateTimeRangeValidator validator (dateTimeRange) in the validators attribute.

<oj-form-layout id="validator-example" label-edge="inside">
  <oj-input-date id="dateTimeRange2" value="{{dateValue2}}" 
                 validators="[[validators]]"
                 label-hint="'validators' attribute">
  </oj-input-date>
</oj-form-layout>

The highlighted code below shows the additions to the viewModel, including the defined function, with options that set the valid minimum and maximum dates and a hint that displays when the user sets the focus in the field.

require(['knockout', 'ojs/ojbootstrap', 'ojs/ojconverterutils-i18n',
          'ojs/ojasyncvalidator-datetimerange', 'ojs/ojconverter-datetime',
          'ojs/ojknockout', 'ojs/ojinputnumber', 'ojs/ojinputtext', 
          'ojs/ojdatetimepicker', 'ojs/ojlabel', 'ojs/ojformlayout'],
    function(ko, Bootstrap, ConverterUtilsI18n, AsyncDateTimeRangeValidator, DateTimeConverter)
    {
      function DemoViewModel() 
      {
        var self = this;
        self.dateValue1 = ko.observable();
        self.todayIsoDate = ko.ConverterUtilsI18n.IntlConverterUtils.dateToLocalIso(new Date()));
        self.milleniumStartIsoDate = ko.observable(ConverterUtilsI18n.IntlConverterUtils.dateToLocalIso(new Date(2000, 00, 01)));
        self.validators = ko.computed(function()
        {
          return [{
            new AsyncDateTimeRangeValidator({
              max: this.todayIsoDate(),
              min: this.milleniumStartIsoDate(),
              hint: {
                'inRange': 'Custom Hint: Enter a date that falls in the current millennium.'
              },
              messageSummary: {'rangeUnderflow': 'Custom: Oops!', 'rangeOverflow': 'Custom: Oops!'},
              converter: new DateTimeConverter.IntlDateTimeConverter({"day":"2-digit","month":"2-digit","year":"2-digit"})
            })
          ];
        }.bind(this));
      };

      Bootstrap.whenDocumentReady().then(
        function ()
        {
          ko.applyBindings(new DemoViewModel(), document.getElementById('validator-example'));      
        }
      );
    });   

When the user runs the page for the en-US locale, the oj-input-date element 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.

Oracle JET elements can also use a regExp validator. If the regular expression pattern requires a backslash, while specifying the expression within an Oracle JET element, you need to use double backslashes. For example:

<oj-input-text 
  …
  validators='[{ 
  "type": "regExp", 
  "options": { 
    "pattern": "\\d+(\\.\\d\{1,2})?", 
    "messageDetail": "Enter a valid number with up to 2 digits of decimal" 
  } 
  }]'>
</oj-input-text>

The options that each validator accepts are specified in API Reference for Oracle® JavaScript Extension Toolkit (Oracle 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 Understand How Validation and Messaging Works in Oracle JET Editable Components.

Use Custom Validators in Oracle JET

You can create custom validators in Oracle JET by extending Validator or by duck typing it.

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 Use the messages-custom Attribute.

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 Validator contract. Because the validator provides the methods expected of a validator, Oracle JET 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 = document.getElementById("cpassword");
        var cpUIVal = cPassword.value;
    
        if (newValue && cpUIVal)
        {
          cPassword.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. getHint is a required method and may return null.
    
      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;
        },
        getHint: function()
           { return null; } 
      };
    }
    
      Bootstrap.whenDocumentReady().then(
        function ()
        {
          ko.applyBindings(new DemoViewModel(), document.getElementById('custom-validator-example'));
        }
      );
    });
  2. Add code to your app 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 oj-input-password elements. The first oj-input-password element uses RegExpValidator to validate that the user has input a password that meets the app's password requirements. The second oj-input-password element uses the equalToPassword validator to verify that the password in the second field is equal to the password entered in the first field.

    <oj-form-layout id="custom-validator-example" label-edge="inside">
      <oj-input-password id="password" name="password" required value="{{password}}"
          label-hint="Password"
          help.instruction="Enter at least 6 characters including a number, one uppercase and lowercase letter"
          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."}}]'>
      </oj-input-password>
      <oj-input-password id="cpassword" name="cpassword" value="{{passwordRepeat}}"
          label-hint="Confirm Password"
          validators="[[[equalToPassword]]]"></oj-input-password>
    </oj-form-layout>

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

About Asynchronous Validators

Oracle JET input components support asynchronous server-side validation via the validators attribute. That means you can check input values against server data without the need to submit a form or refresh a page.

For example, in a form that collects new user data, you can have a validator on the e-mail field to check if the input value has been registered previously.

You can also set number range validators that check against volatile data. For example, on an e-commerce website, you can check the user’s cart against the available inventory, and inform the user if the goods are unavailable without them submitting the cart for checkout.

The Oracle JET Cookbook has a sample that uses the validators attribute and dummy data to simulate server-side validation.

The following code shows an oj-input-text element with the validators attribute set to validators and asyncValidator observables in the JavaScript code. The validators attribute must duck-type AsyncValidator to fulfill the API contract required to create the asynchronous validator.

<oj-form-layout id="fl1" label-edge="top">
    <oj-input-text id="text-input" required 
        label-hint="Quantity Limit"
        on-valid-changed="[[validChangedListener]]"
        validators="[[validators, asyncValidator]]"
        value="{{quantityLimit}}"
        converter= '{
              "type":"number", 
              "options": {"style": "currency", "currency": "USD", 
              "currencyDisplay": "code", "pattern": "¤ ##,##0.00"}}'>     
     </oj-input-text>      
</oj-form-layout>

The following JavaScript code shows the number range validator created in the asyncValidator object that returns a Promise.

self.asyncValidator = {
     // 'validate' is a required method
     // that is a function that returns a Promise
     validate: function (value) {
       // used to format the value in the validation error message.
       var converterOption =
         {
          style: 'currency',
          currency: 'USD',
          currencyDisplay: 'code',
          pattern: '¤ ##,##0.00'
         };
  
       // As of JET 8.0, by default JET's validators are AsyncValidators.
       var numberRangeValidator =
         new AsyncNumberRangeValidator(
           { min: 100, max: 10000, converter: converterOption });
  
       // eslint-disable-next-line no-undef
       return new Promise(function (resolve, reject) {
         // We could go to the server and check the
         // user's credit score and based on that
         // credit score use a specific number range validator.
         // We mock a server-side delay
         setTimeout(function () {
           numberRangeValidator.validate(value).then(
             // eslint-disable-next-line no-unused-vars
             function (result) {
               /* handle a successful result */
               resolve();
             },
             function (e) {
               /* handle an error */
               var converterInstance =
                 new NumberConverter.IntlNumberConverter(converterOption);
               reject({
                 detail: e + ' Your value is ' +
                   converterInstance.format(value) + '.'
               });
             });
            }, 1000);
          });
        },
        // 'hint' is an optional field that returns a Promise
        'hint': new Promise(function(resolve, reject) {
          ...
        })
      };  

Note:

A Promise object in JavaScript represents a value that may not be available yet, but will be resolved at some point in the future. In asynchronous validation, the AsyncValidator.validate() function returns a Promise that evaluates to Boolean true if validation passes and if validation fails, it returns an Error. For more, see the validators attribute section of ojInputText or see Promise (MDN).

For the full Cookbook sample, see Async Validators.