7 入力の検証および変換

Oracle JETには、oj-comboboxoj-input*oj-text-areaなど、多数のOracle JET編集可能要素に対するバリデータおよびコンバータが含まれています。これらをそのまま使用することも、Oracle JETアプリケーションでの入力を検証および変換するためにカスタマイズすることもできます。

oj-checkboxsetoj-radiosetoj-selectなどの一部の編集可能要素には、組込みバリデータを暗黙的に作成するrequired値の単純な属性が含まれます。

ノート:

前述のoj-input*は、特に、oj-input-date-timeoj-input-textoj-input-passwordなどの入力コンポーネントのファミリを指します。

Oracle JETバリデータおよびコンバータについて

Oracle JETには、ユーザー入力文字列をアプリケーションで使用できるデータ型に変換するコンバータ・クラス、およびそれらの入力文字列に検証ルールを強制するバリデータ・クラスが用意されています。

たとえば、Oracle JETのIntlDateTimeConverterを使用して、ユーザー入力の日付を日付のみのISO文字列に変換し、次にDateTimeRangeValidatorを使用して、指定した日付範囲に対してその入力を検証できます。Oracle JETに含まれるコンバータまたはバリデータがアプリケーションにとって十分でない場合は、カスタムのコンバータまたはバリデータを作成できます。

バリデータについて

すべてのOracle JET編集可能要素はvalue属性をサポートし、ユーザーが値を入力または選択できるUI要素を提供します。これらの要素は、要素に対して値の検証方法を指示するために設定できる、その他の属性もサポートしています。

編集可能要素では、特定の属性が設定されると、標準機能に対する組込みコンバータまたは組込みバリデータ(あるいはその両方)を暗黙的に作成できます。たとえば、requiredプロパティをサポートする編集可能要素では、プロパティがtrueに設定されると必須バリデータを暗黙的に作成します。oj-input-dateoj-input-date-timeoj-input-timeなどの要素では、日時コンバータを作成してその基本機能を実装します。

Oracle JETバリデータについて

次の表では、Oracle JETバリデータについて説明し、APIドキュメントへのリンクを示します。

バリデータ 説明 APIへのリンク モジュール

DateTimeRangeValidator

入力日付が、2つの日付間、2つの時刻間、または2つの日時範囲内にあることを検証します

DateTimeRangeValidator

ojvalidation-datetimerange

DateRestrictionValidator

入力日付が制限された日付でないことを検証します

DateRestrictionValidator

ojvalidation-daterestriction

LengthValidator

入力文字列が指定された長さ以内であることを検証します

LengthValidator

ojvalidation-length

NumberRangeValidator

入力数値が指定された範囲内であることを検証します

NumberRangeValidator

ojvalidation-numberrange

RegExpValidator

正規表現が指定のパターンに一致していることを検証します

RegExpValidator

ojvalidation-regexp

RequiredValidator

必須エントリが存在していることを検証します

RequiredValidator

ojvalidation-required

Oracle JETコンポーネントの検証属性について

コンポーネントがサポートする属性はAPIの一部で、次の検証固有の属性がほとんどの編集可能要素に適用されます。

要素の属性 説明

converter

指定すると、要素で作成される内部コンバータに対してconverterインスタンスが使用されます。oj-input-textなどの要素では、値を数値または日付値に変換する(その逆も同じ)場合にこの属性の指定が必要になることがあります。

countBy

LengthValidatorに対してcountByを指定すると、バリデータのデフォルトのカウント動作を変更できるようになります。デフォルトでは、このプロパティはcodeUnitに設定され、JavaScriptの文字列長のプロパティを使用して、UTF-16サロゲート・ペアをlength === 2としてカウントします。これをcodePointに設定すると、サロゲート・ペアがlength ===1としてカウントされます。

max

Oracle JET要素(oj-input-dateoj-input-numberなど)に対して指定すると、要素では暗黙的な範囲バリデータを作成します。

min

Oracle JET要素(oj-input-dateoj-input-numberなど)に対して指定すると、コンポーネントでは暗黙的な範囲バリデータを作成します。

required

Oracle JET要素に対して指定すると、要素では暗黙的な必須バリデータを作成します。

validators

指定すると、要素ではこれらのバリデータと暗黙的なバリデータを使用して、UI値を検証します。ValidatorsまたはAsyncValidatorsを使用して実装し、サーバー上のユーザー入力を非同期的に検証できます。

一部の編集可能要素は、固有の機能に関連がないため特定の検証属性をサポートしていません。たとえば、oj-radiosetおよびoj-checkboxsetは、コンバータが変換する対象がないため、converter属性をサポートしていません。属性の正確なリストおよび使用方法は、要素のAPIドキュメントの属性に関する項を参照してください。Oracle JETのAPIドキュメントについては、『Oracle® JavaScript Extension Toolkit (OracleJET) APIリファレンス』を参照してください。APIリストから表示するコンポーネントを選択してください。

Oracle JETコンポーネントの検証メソッドについて

Oracle JET編集可能要素は、検証目的で次のメソッドをサポートしています。このメソッドのコール方法、およびパラメータと戻り値の詳細は、コンポーネントのAPIドキュメントを参照してください。

要素メソッド 説明

reset()

このメソッドは、すべてのメッセージおよびメッセージ属性(messagesCustom)をクリアして要素をリセットし、属性値を使用して要素の表示値を更新するために使用します。このメソッドがコールされると、ユーザーが入力した値が消去されます。

validate()

このメソッドは、現在の表示値を使用してコンポーネントを検証するために使用します。

要素のメソッドのコール方法、パラメータおよび戻り値の詳細は、『Oracle® JavaScript Extension Toolkit (Oracle JET) APIリファレンス』で、要素のAPIドキュメントのMethodsに関する項を参照してください。コールバックの登録方法、イベントへのバインド方法、およびイベントがトリガーする対象の詳細も記載されています。APIリストから表示するコンポーネントを選択してください。

Oracle JETコンバータについて

Oracle JETでは、日付、日時、数値、色および文字列を変換するコンバータが提供されます。

これらのコンバータは、コンバータ実装の基本契約を定義するConverterオブジェクトを拡張します。コンバータAPIは、ECMAScript国際化API仕様(ECMA-402 Edition 1.0)に基づき、ロケール・データに対してUnicode共通ロケール・データ・リポジトリ(CLDR)を使用します。両方のコンバータはコンストラクタを介して初期化され、API仕様で定義されたオプションを受け入れます。ECMA-402 API仕様の詳細は、https://www.ecma-international.org/publications-and-standards/standards/ecma-402/を参照してください。Unicode CLDRの詳細は、http://cldr.unicode.orgを参照してください。

Oracle JET実装では、追加オプションを導入することによって、ECMA-402仕様が拡張されます。コンバータは、Oracle JETコンポーネントで使用したり、ページで直接インスタンス化して使用できます。各コンバータには、サポートする変換オプションを指定するConverterOptions型定義があります。次の表では、使用可能なコンバータについて説明し、各コンバータのConverterOptions型定義でサポートされているプロパティの詳細説明など、各コンバータのAPIドキュメントへのリンクを示します。

コンバータ 説明 APIへのリンク

ColorConverter

Colorオブジェクト形式を変換します

ColorConverter

IntlDateTimeConverter

文字列をISO文字列形式(yyyy-mm-dd)に解析するか、ISO文字列を標準の文字列形式に変換します。たとえば:

  • 10/12/2020 ---> 2020-10-12
  • 2020-10-12 ---> 10/12/2020

IntlDateTimeConverter

NumberConverter

文字列を数値に変換し、数値をロケール固有の文字列に書式設定します

NumberConverter

BigDecimalStringConverter

BigDecimal文字列をロケール固有の文字列に変換します。非常に大きい数値(Number.MAX_SAFE_INTEGERより大きい)および大規模なスケールの数値(17桁を超える小数)に使用します。文字列値を想定するコンポーネント(oj-c-input-textなど)でのみ使用できます。

BigDecimalStringConverter

LocalDateConverter

日付のみのISO文字列を書式設定された文字列に、または文字列を日付のみのISO文字列に変換します

LocalDateConverter

Oracle JETコンバータは、ユーザー入力が適切なパターンと完全に一致しない場合に、数値および日付の寛大な解析をサポートしています。パーサーは、特定のコンバータの寛大さルールに基づいて寛大な解析を実行します。たとえば、NumberConverterBigDecimalStringConverterの両方が予期しない文字を削除します。ConverterOptions型定義には通常、lenientParseプロパティが含まれます。このプロパティは、ユーザー入力が予想される入力と一致する、または例外がスローされるようにnoneに設定できます。詳細は、使用しているコンバータのAPIドキュメントを参照してください。

RequireJSおよびojs/ojvalidation-datetimeまたはojs/ojvalidation-numberモジュールを使用する場合、Oracle JETコンバータで使用するロケール記号およびデータを保持するリソース・バンドルは、ページに設定されたロケールに基づいて自動的にダウンロードされます。アプリケーションでRequireJSを使用しない場合、ロケール・データは自動的にダウンロードされません。

コンバータは、Oracle JETコンポーネントで使用したり、ページで直接インスタンス化して使用できます。

Oracle JETコンポーネントでのOracle JETコンバータの使用

ユーザー入力を受け入れるOracle JETコンポーネント(oj-c-input-date-textなど)には、ユーザー入力を解析する暗黙的なコンバータがすでに含まれています。ただし、データの変換時にかわりに使用される明示的なコンバータをコンポーネントに指定することもできます。

次の例では、暗黙的なコンバータを使用して「12/25/24」の入力を「12/25/2024」としてレンダリングする間に「abc」と入力すると、oj-c-input-date-textコンポーネントはエラー・メッセージを表示します。

解析操作または書式設定操作時にエラーが発生した場合にコンバータがスローするエラーはConverterErrorオブジェクトで表され、エラー・メッセージはタイプがMessageのオブジェクトで表されます。Oracle JETコンバータが使用するメッセージは、Oracle JETに付属している翻訳バンドルに定義されたリソースです。


暗黙的なコンバータを使用したoj-c-input-date-text

コンバータをコンポーネントのコンバータattributeに直接指定することもできます(存在する場合)。たとえば、oj-c-input-date-textコンポーネントは、converter属性を使用して、コンポーネントがレンダリングする日付スタイルを、LocalDateConverterでサポートされているコンバータ・オプションの1つに変更します。


明示的なコンバータを使用したoj-c-input-date-text

Oracle JETにおけるタイムゾーン・サポートの理解

Oracle JET入力コンポーネント(oj-input-date-timeなど)では、ローカル・タイムゾーン入力をサポートしています。JavaScriptのIntl.DateTimeFormat APIに依存するOracle JETのIntlDateTimeConverterを使用して、タイムゾーン・サポートを有効にできます。

次のイメージでは、入力日時コンポーネントのconverter属性は、タイムゾーンがAmerica/Los_AngelesAsia/Hong_Kongかに応じて、2013-12-02T04:00:00Zの入力時間を適切にレンダリングするコードを参照します。

Oracle JETのIntlDateTimeConverterの詳細は、IntlDateTimeConverterを参照してください。

Oracle JETバリデータについて

Oracle JETバリデータは、コール元がバリデータ・インスタンスをカスタマイズできるようにするプロパティを提供します。プロパティはバリデータのAPIの一部として記述されます。コンバータのインスタンスを1つしか要素に設定できないコンバータとは異なり、1つ以上のバリデータを要素に関連付けることができます。

ユーザーが要素と対話してその値を変更すると、その要素に関連付けられたバリデータが順に実行されます。値が検証ルールに違反する場合、value属性は移入されず、バリデータによって、エラーが発生した要素が強調表示されます。

バリデータは、Oracle JET要素で使用したり、ページで直接インスタンス化して使用できます。

Oracle JETコンポーネントでのOracle JETバリデータの使用

Oracle JET編集可能要素(oj-input-textoj-input-dateなど)は、サポートする特定の属性(requiredminmaxなど)に基づいて暗黙的にバリデータを設定したり、コンポーネントのvalidators属性を使用して1つ以上のバリデータを設定する方法を提供して明示的にバリデータを設定できます。

たとえば、次のコードは、コンポーネントによって暗黙的に提供されるデフォルト・バリデータを使用するoj-input-date要素を示しています。oj-input-dateは、minおよびmax属性を読み取ると、暗黙的なDateTimeRangeValidatorを作成します。

import { h } from "preact";
import * as ConverterUtilsI18n from "ojs/ojconverterutils-i18n";
import "ojs/ojformlayout";
import "ojs/ojdatetimepicker";

export function Content() {
  let todayIsoDate: string = ConverterUtilsI18n.IntlConverterUtils.dateToLocalIso(
    new Date()
  );

  let milleniumStartIsoDate: string = ConverterUtilsI18n.IntlConverterUtils.dateToLocalIso(
    new Date(2000, 0, 1)
  );

  return (
    <div class="oj-web-applayout-max-width oj-web-applayout-content">
      <oj-form-layout id="formLayout1" columns={1}>
        <oj-input-date
          id="dateTimeRange1"
          min={milleniumStartIsoDate}
          max={todayIsoDate}
          labelHint="'min' attribute and 'max' option"
        ></oj-input-date>
      </oj-form-layout>
    </div>
  );
}

ユーザーがページを実行すると、oj-input-date要素により、カレンダ・アイコンの付いた入力フィールドが表示されます。入力したデータが適切な範囲内でない場合は、組込みバリデータによってエラー・メッセージと適切な範囲が表示されます。

input-validator-message-vdom.pngの説明が続きます
illustration input-validator-message-vdom.pngの説明

検証が失敗したときにOracle JETバリデータがスローするエラーはValidatorErrorオブジェクトで表され、エラー・メッセージはタイプがMessageのオブジェクトで表されます。Oracle JETバリデータがエラーをスローするときに使用するメッセージとヒントは、Oracle JETに付属している翻訳バンドルに定義されたリソースです。

要素のvalidators属性にバリデータを指定することもできます(存在する場合)。次のコード・サンプルは、DateTimeRangeValidatorバリデータ(dateTimeRange)をvalidators属性に指定する関数をコールする別のoj-input-date要素を示しています。

import { h } from "preact";
import { useMemo } from "preact/hooks";
import * as ConverterUtilsI18n from "ojs/ojconverterutils-i18n";
import "ojs/ojformlayout";
import "ojs/ojdatetimepicker";
import AsyncDateTimeRangeValidator = require("ojs/ojasyncvalidator-datetimerange");
import * as DateTimeConverter from "ojs/ojconverter-datetime";

export function Content() {
  let todayIsoDate: string = ConverterUtilsI18n.IntlConverterUtils.dateToLocalIso(
    new Date()
  );

  let milleniumStartIsoDate: string = ConverterUtilsI18n.IntlConverterUtils.dateToLocalIso(
    new Date(2000, 0, 1)
  );

  const dateRange = useMemo(() => {
    return [
      new AsyncDateTimeRangeValidator({
        max: todayIsoDate,
        min: milleniumStartIsoDate,
        hint: {
          inRange:
            "Enter a date that falls in the current millennium and "
            + "is not greater than today's date.",
        },
        converter: new DateTimeConverter.IntlDateTimeConverter({
          day: "2-digit",
          month: "2-digit",
          year: "2-digit",
        }),
      }),
    ];
  }, [todayIsoDate, milleniumStartIsoDate]);

  return (
    <div class="oj-web-applayout-max-width oj-web-applayout-content">
      <oj-form-layout id="formLayout1" columns={1}>
        <oj-input-date
          id="dateTimeRange2"
          labelHint="'dateTimeRange' type in 'validators' option"
          validators={dateRange}
        ></oj-input-date>
      </oj-form-layout>
    </div>
  );
}

ユーザーがen-USロケールでページを実行すると、oj-input-date要素によって入力フィールドが表示されます。このフィールドは、ユーザーの入力日付が01/01/2000から現在日付の間である必要があります。日付値をフィールドに入力するとき、日付コンバータは、日付を明確に解析できる場合にかぎり代替入力を受け入れます。これによって、エンド・ユーザーが日付値を入力するときの許容範囲が大きく広がります。たとえば、1-2-3と入力すると、Dateは2003年1月2日に変換されます。Date値が、バリデータに設定されたDate範囲内である場合も、その値は受け入れられます。検証に失敗すると、コンポーネントでエラーが表示されます。

Oracle JET要素では、regExpバリデータも使用できます。正規表現パターンにバックスラッシュが必要で、Oracle JET要素内に式を指定する場合、二重のバックスラッシュを使用する必要があります。各バリデータが受け入れるオプションは、『Oracle® JavaScript Extension Toolkit (Oracle JET) APIリファレンス』に指定されています。

Oracle JETでのカスタム・バリデータの使用

Oracle JETでは、validators属性から組込みバリデータのように参照できるカスタム・バリデータを作成できます。

次の図は、ユーザーのパスワードが一致しない場合にエラー・メッセージを表示するカスタム・バリデータを示しています。

カスタム・バリデータを作成および使用するには:

  1. Oracle JETコンポーネントのvalidators属性からカスタム・バリデータを参照します。
    次の例では、「パスワードの確認」入力フィールドをレンダリングするコンポーネントは、validators属性からconfirmPasswordValidator変数を参照します。
    <oj-c-input-password
       id="cpassword"
       value={passwordRepeat}
       onvalueChanged={handlePasswordRepeat}
       validators={confirmPasswordValidator}
       label-hint="Confirm Password"
       mask-icon="visible">
      </oj-c-input-password>
  2. カスタム・バリデータを記述します。
    次の例では、validateEqualToPassword関数は、「パスワードの確認」フィールドに入力した値が、「パスワード」フィールドに以前に入力した値と一致することを検証します。confirmPasswordValidator変数は、useMemoフックを使用して、confirmPasswordValidatorvalidateEqualToPasswordの変更時にのみ再計算されるようにします。
    . . . 
    const validateEqualToPassword = useCallback(
      (value: string) => {
        if (value && value !== password) {
          throw new Error(
            "The passwords must match!"
          );
        }
        setError(null);
        return Promise.resolve();
      },
      [password]
    );
    
    const confirmPasswordValidator = useMemo(
      () => [{ validate: validateEqualToPassword }],
      [validateEqualToPassword]
    );
    . . .

非同期バリデータについて

Oracle JET入力コンポーネントでは、validators属性を介した非同期サーバー側検証をサポートしています。つまり、フォームを送信したり、ページをリフレッシュすることなく、サーバー・データに対する入力値をチェックできます。

次の2つのシナリオ例は、どのような場合に、非同期のサーバー側検証を使用できるかを示しています:

  • 新しいユーザー・データを収集するフォームで、電子メール・フィールドの入力内容を検証し、入力値が事前に登録されているかどうかを確認します。
  • 揮発性データを確認する数値範囲バリデータを設定します。たとえば、e-コマースのWebサイトで、ユーザーのカートを利用可能在庫に対してチェックし、商品の利用可能在庫がなければ、ユーザーがカートを送信して支払に進む前に、そのことをユーザーに通知できます。

次のコードは、validators属性が関数の配列(validatorsおよびasyncValidator)に設定されたoj-c-input-text要素を示しています。同期バリデータvalidatorsは、入力値が500かどうかをチェックします。その場合、エラーがスローされます。非同期バリデータasyncValidatorは、Promiseを返します。Promiseとは、まだ利用可能になっていない可能性があるが、将来のある時点で解決される値を表しています。Promiseは、検証にパスするとtrueと評価され、検証に失敗した場合はエラーを返します。AsyncNumberRangeValidatorは、入力値が指定された範囲(100から1000)内にあるかどうかをチェックします。検証を実行する前に、setTimeoutを使用してサーバー側の遅延をシミュレートします。非同期バリデータの作成に必要なAPI規約に準拠するためには、validators属性はタイプをAsyncValidatorにする必要があります。

import { h } from "preact";
import "ojs/ojformlayout";
import { useState } from "preact/hooks";
import AsyncNumberRangeValidator = require("ojs/ojasyncvalidator-numberrange");
import { CInputTextElement } from "oj-c/input-text";
import "oj-c/input-text";

export function Content() {
  const [quantityLimit, setQuantityLimit] = useState("");

  const onValueChanged = (event: CInputTextElement.valueChanged<string>) => {
    setQuantityLimit(event.detail.value);
  };

  const minQuantity = 100;
  const maxQuantity = 1000;

  // synchronous validator.
  const validators = {
    validate: (value: string | number) => {
      if (value === 500 || value === "500") {
        throw new Error("500 is invalid");
      } else {
        return;
      }
    },
    getHint: () => {
      return "To see an immediate error from the synchronous validator (validators), enter 500.";
    },
  };

  // asynchronous validator.
  const asyncValidator = {
    validate: (value: string | number) => {
      const numberRangeValidator = new AsyncNumberRangeValidator({
        min: minQuantity,
        max: maxQuantity,
      });

      return new Promise<void>((resolve, reject) => {
        // Simulate server-side delay
        setTimeout(() => {
          numberRangeValidator.validate(value).then(
            () => {
              resolve();
            },
            (e) => {
              // Handle validation error
              reject(
                new Error(
                  `${value} is not in the accepted range of ${minQuantity} - ${maxQuantity}`
                )
              );
            }
          );
        }, 1000);
      });
    },

    hint: new Promise<string>((resolve) => {
      // Simulate server-side delay 
      setTimeout(() => {
        resolve(
          `To see an error from the asynchronous validator (asyncValidator) that appears after 1 second, 
          enter a number outside the range of ${minQuantity} - ${maxQuantity}`
        );
      }, 100);
    }),
  };

  return (
    <div class="oj-web-applayout-max-width oj-web-applayout-content">
      <oj-form-layout columns={1} class="oj-md-margin-4x-horizontal">
        <oj-c-input-text
          id="input-text"
          labelHint="Quantity Limit"
          onvalueChanged={onValueChanged}
          validators={[validators, asyncValidator]}
          value={quantityLimit}
        ></oj-c-input-text>
      </oj-form-layout>
    </div>
  );
}

詳細は、入力テキストvalidators属性の項を参照するか、「Promise (MDN)」を参照してください。