Ignite UI for Angular の igxMask ディレクティブには、日本語(全角)文字の入力を無効にするマスク文字は用意されていません。本記事では、document.body に登録したキャプチャフェーズの compositionstart イベントリスナーで stopPropagation() を行うことで、IME による日本語入力そのものを無効化する方法を紹介します。

igxMask の設定

対象の入力欄には igx-input-groupigxInput を使用し、[igxMask] にマスク書式(ここでは半角英字5文字を表す AAAAA)を指定します。後述の JavaScript 側でこの要素だけを識別できるよう、独自の data-mask-ascii-only 属性を付与しています。

<igx-input-group>
  <input
    igxInput
    type="text"
    [igxMask]="maskFormat"
    [(ngModel)]="inputValue"
    data-mask-ascii-only
  />
</igx-input-group>

compositionstart イベントの処理

data-mask-ascii-only 属性を持つ要素からのイベントかどうかを判定し、対象であれば document.body に登録した compositionstart(キャプチャフェーズ)で stopPropagation() を呼び出します。これにより IgxMaskDirective 自身の compositionstart ハンドラーにイベントが渡らなくなり、IME による日本語入力の確定処理そのものを止められます。ただしこれだけでは変換候補ウィンドウの表示までは止まらないため、一時的に入力要素を disabled にして読み取り専用状態にし、候補表示もキャンセルしています。同じ仕組みで paste イベントも監視し、クリップボードから貼り付けられた文字列に非ASCII文字が含まれる場合は貼り付け自体をキャンセルします。このリスナーはアプリ起動時に1度登録すればよいため、main.tsimport './app/ascii-only-mask.bootstrap' のように読み込んでいます。

// イベントの発生元が、マスク入力であるか否かを判定します。
// class ではなく data-mask-ascii-only 属性で判定することで、スタイリング用の
// class とは役割を分離し、この属性がついた対象のみASCII英数字以外を無効化します。
const isTargetMaskInput = (target: EventTarget | null): target is HTMLInputElement => {
  return target instanceof HTMLInputElement && target.hasAttribute('data-mask-ascii-only');
}

// 貼り付けられた文字列に非ASCII文字が含まれるかどうかの判定に使用します。
const nonAsciiRegex = /[^\x00-\x7F]/;

// IME による入力開始のイベントを捕捉し、対象がマスク入力の場合は処理をキャンセルします。
// キャプチャフェーズでイベントを捕捉し stopPropagation することで、マスク入力
// コンポーネント(IgxMaskDirective)自身の compositionstart ハンドラーには
// そもそもイベントが到達しなくなります。
document.body.addEventListener('compositionstart', (event) => {
  if (!isTargetMaskInput(event.target)) return;

  event.stopPropagation();

  // ただしそれだけだと、IME 入力中の候補表示まではキャンセルされないため、
  // disabled を一時的に true にして読み取り専用にすることで、候補表示もキャンセルします。
  const inputElement = event.target;
  const selectionStart = inputElement.selectionStart;
  const selectionEnd = inputElement.selectionEnd;
  inputElement.disabled = true;

  // setTimeout を使用して、IME の候補表示のキャンセルを完了した後に disabled を false に戻します。
  setTimeout(() => {
    inputElement.disabled = false;
    inputElement.focus();
    if (selectionStart !== null && selectionEnd !== null) {
      inputElement.setSelectionRange(selectionStart, selectionEnd);
    }
  }, 0);
}, true);


// クリップボードからの貼り付けイベントを捕捉し、対象がマスク入力の場合は非ASCII文字を含む場合に処理をキャンセルします。
document.body.addEventListener('paste', (event) => {
  if (!isTargetMaskInput(event.target)) return;

  const textToPaste = event.clipboardData?.getData('text/plain');
  if (textToPaste && nonAsciiRegex.test(textToPaste)) {
    event.preventDefault();
    event.stopPropagation();
  }
}, true);

実行結果

マスク入力欄で日本語入力(ひらがな・漢字への変換)を試みても、IME の変換候補が表示されず、入力欄には半角英数字のみがマスク書式に従って反映されることを確認できます。クリップボードから日本語文字列を貼り付けた場合も、貼り付けが行われないことを確認できます。

Tagged:

製品について

Ignite UI for Angular