5. 操作性向上・制御

この章では、操作性向上のため、各種ライブラリを用いて操作を補助したり制限する方法を説明する。

5.1. ショートカットキー制御

5.1.1. 概要

ショートカットキー制御とは、指定したキー操作を無効化したり、動作を変更することである。

ここでは、Mousetrapを用いて、 Ctrl + c および Ctrl + v による「コピーアンドペースト」、および Ctrl + s による「ページの保存」の動作を変更する方法を説明する。

利用ライブラリ サンプル 参考ページ
Mousetrap コピー・ペースト無効化 Mousetrap - Keyboard shortcuts in Javascript

5.1.2. 利用方法

HTMLでは、Mousetrapと、ショートカットキーを制御するために実装したJavaScript(disable-copy-paste.js)を読み込む。

留意点として、Mousetrapの仕様上、textareainputselect要素にフォーカスがある場合は、キー操作時の動作は変更されない。 これらの要素内でキー操作を変更する場合は、対象の要素にmousetrapクラスを指定する必要がある。

<textarea id="area1">No key-controls executed for this text-area.</textarea>

<!-- (1) -->
<textarea id="area2" class="mousetrap">key-controls for copy(Ctrl + c) and paste(Ctrl + v) is disabled for this text-area.</textarea>

<!-- (1) -->
<textarea id="area3" class="mousetrap">disable copy(Ctrl + c) and paste(Ctrl + v), and execute original function when key-control for save(Ctrl + s) is used.</textarea>

<!-- (2) -->
<script src="../lib/vendor/mousetrap/1.6.2/mousetrap.min.js"></script>
<script src="js/disable-copy-paste.js"></script>
項番 説明
(1)
キー制御を有効化するため class属性に “mousetrap” を指定する。
(2)
Mousetrapと、独自に実装したJavaScriptを読み込む。

JavaScript(disable-copy-paste.js)では、Mousetrap.bind関数を用いて次の処理を実行する。

// disable-copy-paste.js

'use strict';

window.onload = function () {

  // (1)
  Mousetrap.bind('ctrl+c', function () {
    return false;
  });

  // (2)
  Mousetrap.bind('ctrl+v', function () {
    return false;
  });

  // (3)
  Mousetrap.bind('ctrl+s', function () {
    if (document.activeElement.id === 'area3') {
      alert('data is saved');
      return false;
    }

    return true;
  });

};
項番 説明
(1)
Ctrl + c 実行時の操作を変更する。ここでは操作を無効化する。
(2)
Ctrl + v 実行時の操作を変更する。ここでは操作を無効化する。
(3)
Ctrl + s 実行時の操作を変更する。ここではフォーカスが #area3 にある場合のみ処理を変更する。

標準動作を無効化するためにはMousetrap.bind関数のコールバック関数でfalseを返す。trueを返すと標準動作が行われる。

Note

ショートカットキー操作で起動できる動作は、JavaScriptで実行できる動作のみである。 例えば、 Ctrl + s 操作による「ページの保存」のようなブラウザの標準動作は、JavaScriptから実行できないため、これを別のショートカットキー操作に割り当てることは不可能である。

Note

対応可能なキーは Mousetrapの公式リファレンス の「Supported Keys」を参照すること。なお、「F12」など、「Supported Keys」に記載は無いが、制御可能なものもある。Mousetrapのソースコードを参照すること。

5.2. 範囲選択防止

5.2.1. 概要

範囲選択防止とは、マウスやキー操作によってページ内の文字列等がハイライトすることを抑止する機能である。
範囲選択防止は、カスケード スタイル シート (CSS) プロパティであるuser-selectプロパティを使用する。user-selectプロパティは各ブラウザが独自に実装しており、設定がそれぞれ異なる。また、 Internet Explorer は Firefox ・ Chrome と比べてハイライトの挙動に差異がある。
ここでは、ブラウザ毎の設定方法や、Internet Explorer の挙動の差異の吸収方法を紹介する。

Note

user-selectプロパティは World Wide Web Consortium (W3C) CSS Level 3(https://www.w3.org/TR/css-ui-3/)に含まれておらず、CSS Level 4(https://www.w3.org/TR/css-ui-4/)に記述されているものの、草案(Working Draft)に留まっている。

Warning

後述する範囲選択防止の実現のため用いるCSSやJavaScriptは、ブラウザ毎に挙動が異なり、またブラウザバージョンアップ後に動作が保証されているわけではない。本ガイドラインで紹介する実現方法については動作確認しているが、ブラウザのバージョンアップなども考慮した上で、範囲選択防止の要件を取り込むかどうか検討すること。

利用ライブラリ サンプル 参考ページ
jQuery -

5.2.2. 利用方法

ここでは、ページ全体、またはページの一部がハイライトできないよう制御する方法を紹介する。

5.2.2.1. ページ全体の範囲選択防止

ページ全体がハイライトできないよう制御する方法を紹介する。
HTMLでは、jQueryと、ハイライトを防止するために実装したJavaScript(prevent-range-selection-all-elements.js)を読み込む。
<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="js/prevent-range-selection-all-elements.js"></script>
JavaScript(prevent-range-selection-all-elements.js)では、html要素にcss関数を用いてuser-selectプロパティを指定する。
// (1)
$('html').css({
  'user-select' : 'none',

  // (2)
  '-moz-user-select' : 'none',

  // (3)
  '-webkit-user-select' : 'none',

  // (4)
  '-ms-user-select' : 'none'
});
項番 説明
(1)
CSSによる範囲選択防止を実装する。
(2)
ブラウザがFirefoxの場合の定義を設定する。
(3)
ブラウザがSafari、Chromeの場合の定義を設定する。
(4)
ブラウザがInternet Explorerの場合の定義を設定する。

5.2.2.2. ページ内の特定要素の範囲選択防止

ここでは、ページ内の特定要素をハイライトできないよう制御する方法を紹介する。
HTMLではハイライトを不可とする要素のクラス属性にdisableを設定する。なお、クラス名はJavaScriptのセレクタと一致していれば他の名称でも問題ない。
<p class="disable">
    HTMLの特定の要素を選択不可とします
</p>
また、jQueryと、ハイライトを防止するために実装したJavaScript(prevent-range-selection-target-elements.js)を読み込む。
<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="js/prevent-range-selection-target-elements.js"></script>
JavaScriptでは、クラス属性にdisableを設定した要素にcss関数を用いてuser-selectプロパティを指定する。
// (1)
$('.disable').css({
  'user-select' : 'none',
  '-moz-user-select' : 'none',
  '-webkit-user-select' : 'none',
  '-ms-user-select' : 'none'
});
項番 説明
(1)
CSSによる範囲選択防止。class="disable"を設定した要素をハイライトできないように実装する。

Note

INPUT・TEXTAREAにuser-selectプロパティを設定した場合、ブラウザ毎に挙動が異なるため設定しないこと。


Internet Explorerは特定要素をハイライト不可としても、以下の操作を行うことでハイライトできる。
  • Ctrl + a を押下する。
  • ハイライト可の要素から不可の要素をマウスでドラッグする。
それらを防止するための方法を紹介する。
Ctrl + a を防止する方法を以下に示す。
keydownイベントをトラップし、 Ctrl + a が押下された場合にfalseを返却する。
// (1)
$(document).on('keydown', keyDownEvent);

// (2)
function keyDownEvent(event) {

  // (3)
  if (!isIE()) {
    return true;
  }

  // (4)
  if (event.ctrlKey && event.key === 'a') {

    // (5)
    if (event.target.nodeName !== 'INPUT' &&
        event.target.nodeName !== 'TEXTAREA') {

      // (6)
      return false;
    }
  }
  return true;
}
項番 説明
(1)
キー押下実行時に関数を呼び出す。
(2)
キー操作が行われた場合に実行する関数を定義する。
(3)
独自関数によるブラウザ判定を実施し、Internet Explorer以外の場合は処理を終了する。
(4)
キー押下が Ctrl + a の場合の条件を実装する。
(5)
入力系の要素は制御対象外とする。
(6)
入力系以外の要素の場合にはキー操作を無効とする。

Note

Ctrl + a の制御はMousetrapを用いて実現することもできる。ショートカットキー制御 を参照すること。

次に、ドラッグを防止する方法を以下に示す。
範囲選択を開始した要素のみ選択可能とし、カーソルが別要素をマウスオーバーした時点で範囲選択を解除する。
selectstartイベント発生時に範囲選択開始時点の要素を取得し、mouseoverイベント発生時に開始時点の要素と一致しているかチェックする。不一致の場合は範囲選択開始時点の要素を格納する。また、mouseupイベント発生時に変数を初期化する。
// (1)
$(document).on('mouseup', mouseUpEvent);
$(document).on('selectstart', mouseSelectEvent);
$(document).on('mouseover', mouseOverEvent);

// (2)
var select = false;
var range = null;
var selectStartNode = '';

// (3)
function mouseUpEvent() {
  if (!isIE()) {
    return true;
  }

  // (4)
  select = false;
  range = null;
  selectStartNode = '';

  return true;
}

// (5)
function mouseSelectEvent(event) {
  if (!isIE()) {
    return true;
  }

  var selection = window.getSelection();

  // (6)
  if (selection.rangeCount === 0) {
    return true;
  }

  // (7)
  if (event.target.tagName === 'HTML' ||
      event.target.tagName === 'BODY') {
    selection.removeAllRanges();
    return false;
  }

  // (8)
  select = true;
  range = selection.getRangeAt(0);
  selectStartNode = selection.anchorNode.parentNode;

  return true;
}

// (9)
function mouseOverEvent(event) {
  if (!isIE()) {
    return true;
  }

  // (10)
  if (select && event.target !== selectStartNode) {
    var selection = window.getSelection();
    var newRange = document.createRange();
    newRange.selectNode(range.startContainer);
    selection.removeAllRanges();

    // (11)
    selection.addRange(newRange);
  }
  return true;
}
項番 説明
(1)
マウス操作時に範囲選択を防止するための関数を実行する。
(2)
範囲選択制御に使用する変数(範囲選択ステータス、範囲選択開始時の領域、範囲選択開始時の要素名)を定義する。
(3)
マウスキーが離された時に実行する関数を定義する。
(4)
範囲選択制御に使用する変数を初期化する。
(5)
範囲選択開始時に実行する関数を定義する。
(6)
INPUT・TEXTAREAを除き、範囲選択を行っていない場合は対象外とする。
(7)
タグがBODY・HTMLの場合は範囲選択不可とする。
(8)
範囲選択制御に使用する変数をそれぞれ更新する。
(9)
マウスオーバー時に実行する関数を定義する。
(10)
カーソルが別要素に到達したら文字列選択をクリアする。
(11)
範囲選択開始時の要素を設定することで、ハイライトしている範囲を限定する

Note

上記のサンプルでは、ブラウザ判定をisIE関数で行っている。isIEの実装を以下に示す。

function isIE() {
  var userAgent = window.navigator.userAgent.toLowerCase();
  if (userAgent.match(/trident/)) {
    return true;
  }
  return false;
}

Internet Explorerの判定は、ユーザエージェントに特定の文字列(trident)が含まれるかどうかで行っている。ただし、ユーザエージェントはブラウザのバージョンアップ等で変更される可能性があるため、導入する場合は判定方法を別途検討すること。

Warning

Internet Explorerにおいて、ブロック要素とインライン要素を入れ子にし、インライン要素に範囲選択防止の設定をした場合、ブロック要素上をドラッグ、またはダブルクリックすることでインライン要素をハイライトできる。

HTMLの実装例と範囲選択防止が機能しない例のイメージを以下に示す。

<p>
    Make particular element of HTML <span class="disable">non-selectable</span>.<br />
    Try to select the sentence above without mouse-overing "non-selectable".
</p>
マウスドラッグによる範囲選択防止を設定した要素のハイライト例

図: マウスドラッグによる範囲選択防止を設定した要素のハイライト例

本事象はInternet Explorerがハイライト可の要素を含めることで、不可の要素もハイライトできてしまうことに起因しており、範囲選択防止機能では制御できない。導入する際はブロック要素を範囲選択防止の対象とすること。

5.3. ボタンの活性状態の変更

5.3.1. 概要

ここでは、jQueryを用いて、ボタンの活性状態を変更する方法を説明する。

例として、チェックボックスをチェックしないと送信ボタンが押せないサンプルを用いて説明する。

利用ライブラリ サンプル 参考ページ
jQuery ボタンの活性・非活性 -

5.3.2. 利用方法

HTMLでは、jQueryと、ボタンの活性状態を制御するために実装したJavaScript(enable-and-disable-button.js)を読み込む。

<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="js/enable-and-disable-button.js"></script>

JavaScript(enable-and-disable-button.js)では、チェックボックスのchangeイベントハンドラ内で、 チェック状態に応じて送信ボタンの活性状態を変更する。

// enable-and-disable-button.js

'use strict';

$(function () {

  $('#check').on('change', function () {
    var $submit = $('#submit');

    if (this.checked) {

      // (1)
      $submit.prop('disabled', false);
    } else {

      // (2)
      $submit.prop('disabled', true);
    }
  });

});
項番 説明
(1)
チェック状態の場合、送信ボタンを活性状態にする。
(2)
非チェック状態の場合、送信ボタンを非活性状態にする。

5.4. 二度押し無効化(二重送信防止)

5.4.1. 概要

ここでは、jQueryを用いて、ボタンの二度押しを無効化する方法を説明する。

例として、ボタンがクリックされたら処理が完了するまでボタンを非活性化することで、二度押しを無効化するサンプルを用いて説明する。

利用ライブラリ サンプル 参考ページ
jQuery 二度押し無効化(ボタン非活性化) -

5.4.2. 利用方法

HTMLでは、jQueryと、二度押しを無効化するために実装したJavaScript(prevent-continuous-click.js)を読み込む。

<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="js/prevent-continuous-click.js"></script>

JavaScript(prevent-continuous-click.js)は、次のように実装する。

// prevent-continuous-click.js

'use strict';

$(function () {

  $('#the-form').on('submit', function (e) {
    e.preventDefault();

    var $form = $(this),
        $button = $form.find('[type=submit]');

    // (1)
    $button.prop('disabled', true);

    // (2)
    $.ajax({
      url : $form.attr('action'),
      type : $form.attr('method'),
      data : $form.serialize()
    })

    .then(function () {
      console.log("成功")
    })

    .catch(function() {
      console.log("失敗")
    })

    // (3)
    .then(function() {
      setTimeout(function () {

        // (4)
        $button.prop('disabled', false);
      }, 2000);
    });
  });
});
項番 説明
(1)
送信ボタンを非活性化する。
(2)
非同期通信を開始する。
(3)
通信処理完了後に実行する関数を指定する。
(4)
送信ボタンを再度活性化する。

Note

本サンプルでは、ボタンの活性状態の変化が分かり易いように、Ajax通信のレスポンスを得てから2秒後にボタンを再活性化している。実際の開発ではsetTimeout関数は不要である。

これにより、送信ボタンがクリックされたら直ちに非活性化し、通信処理が完了後に活性状態に戻す動作が実現され、 二度押し無効化が実現できる。

Note

本サンプルでは、通信失敗時や通信中にブラウザの停止ボタンを押下した場合などを考慮していない。

通信の成功(then)、失敗(catch)にかかわらず、常にボタンが再活性化する。

実際のシステムでは業務要件に合わせて、通信成功/通信失敗、通信終了時それぞれで、活性化する/常に活性化しないなど処理を実装すること。

thencatch の扱いなど、Ajax通信については非同期処理Ajaxを利用した連携も参照すること。

5.4.3. 応用方法

5.4.3.1. 同一フォーム内に複数のボタンを設置する場合

同一フォーム内に複数のボタンを設置する場合、遷移先情報をHTTPパラメータに設定し実現することが多い。 jQueryのsubmitイベントハンドラ内では、本来HTTPパラメータにセットされるはずだった情報が設定されないため、実装を追加する必要がある。

なお、以下のサンプルは Macchinettaオンライン版 開発ガイドライン と連携することを前提としている。

  • HTML
<form:form id="form1" action="${pageContext.request.contextPath}/Doubleclick1/click" modelAttribute="sampleForm" method="POST">
    <form:button id="button-aaa" name="aaa">aaa</form:button>
    <form:button id="button-bbb" name="bbb">bbb</form:button>
</form:form>
  • JavaScript
// (1)
var clickedName = '';

$(function () {

  $('#form1').on('submit', function (e) {

    var $form = $(this),
        $button = $form.find('[type=submit]');

    // (2)
    var input = $("<input>").attr("type", "hidden")
                            .attr("name", clickedName);
    $form.append($(input));

    // (3)
    $button.prop('disabled', true);

  });

  // (4)
  $(':button').on('click', function () {
    clickedName = $(this).attr('name');
  });

});
項番 説明
(1)
押下されたボタンのname属性を格納する。
(2)
複数ボタンを設置した場合、サーバ側のControllerクラスで@RequestMappingのparam属性による振り分けを設定しているため、本来HTTPパラメータで送信されるはずだったButtonのname属性を手動で設定する必要がある。
(3)
送信ボタンを非活性化する。
(4)
押下されたボタンのname属性を取得する関数を定義する。

Note

サーバサイドの複数ボタンの設置については Macchinettaオンライン版 開発ガイドライン ( https://macchinetta.github.io/server-guideline/current/ja/の Macchinetta Server Framework (1.x) Development Guideline ) を参照すること。

また、非同期通信用のボタン等で個別に1ボタンずつ二度押しを無効化したい場合はjQueryのclickイベントハンドラ内でボタン毎に制御を実装する。 例えば以下のようなHTMLの場合、

<form id="form1" action="/server-sampleapp-basic/Doubleclick2/click" method="POST">
    <input type="button" id="executeService1" value="Execute Function 1" />
    <br />
    <input type="button" id="executeService2" value="Execute Function 2" />
    <br />
    <button id="submit" name="submit" type="submit" value="Submit">submit</button>
</form>

非同期通信を実行するボタンに対してはそれぞれ以下のようなJavaScriptを実装する。

// (1)
$('#executeService1').on('click', function () {
  $('#executeService1').prop('disabled', true);
  $(function () {
    $.ajax({
      url: contextPath + '/api/v1/dummyServiceForLoading',
      type: 'POST',
      dataType: 'json',
    }).always(function() {
      $('#executeService1').prop('disabled', false);
    });
  });
});

// (2)
$('#executeService2').on('click', function () {
  $('#executeService2').prop('disabled', true);
  $(function () {
    $.ajax({
      url: contextPath + '/api/v1/dummyServiceForLoading',
      type: 'POST',
      dataType: 'json',
    }).always(function() {
      $('#executeService2').prop('disabled', false);
    });
  });
});
項番 説明
(1)
“Execute Function 1”ボタンを押下した場合に実行する処理を定義する。
(2)
“Execute Function 2”ボタンを押下した場合に実行する処理を定義する。

5.4.3.2. 非同期通信中を表示する場合

ここではAjax処理によって非同期通信処理を実行している間に、画面に通信中である旨を表示するための仕組みを紹介する。
なお、以下のサンプルはサーバサイドと連携することを前提としている。
HTMLは、Ajaxを実行する契機となるボタンと、通信中に表示する文言を設置する。
<button id="executeService">EXECUTE</button>&nbsp;<label id="loadingLabel" style="display: none;">Loading...</label>
“Loading…”はAjax実行中にのみ表示させるため、デフォルトのCSSスタイルにdisplay: none;を指定している。
Javascriptは以下のように実装する。
$(function() {

  // (1)
  $('#executeService').click(function() {

    // (2)
    $('#executeService').prop('disabled', true);

    // (3)
    $('#loadingLabel').fadeIn();

    // (4)
    $(function() {
      $.ajax({
        url: contextPath + '/api/v1/dummyServiceForLoading',
        type: 'POST',
        dataType: 'json',
      })

      .then(function () {
        console.log("成功")
      })

      .catch(function() {
        console.log("失敗")
      })

      .then(function() {

        // (5)
        $('#executeService').prop('disabled', false);

        // (6)
        $('#loadingLabel').fadeOut();
      });
    });
  });
});
項番 説明
(1)
ボタン押下を契機に処理を開始する。
(2)
ボタンを非活性に変更する。
(3)
処理中に表示させる文言をフェードインさせる。
(4)
非同期通信処理を実行する。
(5)
処理完了後にボタンを再度活性化する。
(6)
処理中に表示していた文言をフェードアウトさせる。
このサンプルではボタン押下のタイミングでAjax処理を実行する。
Ajax処理実行の直前でボタンを非活性にしている。これは2度押しによる不具合を回避するために設定する。
CSSスタイルにdisplay: none;を指定し非表示にしていた領域をjQueryのfadeInメソッドを使用することで表示させる。
Ajax処理完了後はthenメソッドを使用することで、処理結果が成功(then)、失敗(catch) のどちらの場合でも実行されるように実装する。

Note

Ajaxを用いたサーバとの非同期通信の詳細については Macchinettaオンライン版 開発ガイドライン ( https://macchinetta.github.io/server-guideline/current/ja/の Macchinetta Server Framework (1.x) Development Guideline ) を参照すること。

5.4.3.3. a要素によるリンクに対して二度押しを無効化する場合

a要素を使用したリンクに対して二度押しを無効化する場合、ボタンのようにdisable属性は使用できない。 このため、二度押しを無効化するためのJavaScriptを独自に実装する必要がある。 以下にサンプルを示す。

  • HTML
<a id="sample" href="#">sample</a>
  • JavaScript
// (1)
var clicked = false;

$(function () {

  // (2)
  $('a').on('click', function () {

    // (3)
    if (clicked) {
      return false;
    };

    // (4)
    clicked = true;

    // (5)
    $(function () {
      $.ajax({
        url: contextPath + '/api/v1/dummyServiceForLoading',
        type: 'POST',
        dataType: 'json',
      }).always(function() {
          clicked = false;
      });
    });
  });
});
項番 説明
(1)
対象のリンクについて押下の未済を判定するための変数を定義する。
(2)
a要素が押下された際のイベントハンドラを定義する。
(3)
押下済みの場合はfalseを返却しリンクを無効化する。
(4)
押下済みでない場合はフラグを立て押下済みとする。
(5)
リンク押下時の動作を実装する。

5.5. 右クリック無効

5.5.1. 概要

ここでは、jQueryを用いて、右クリックを無効化する方法を説明する。

利用ライブラリ サンプル 参考ページ
jQuery 右クリック無効化 -

5.5.2. 利用方法

HTMLでは、jQueryと、右クリックを無効化するために実装したJavaScript(disable-right-click.js)を読み込む。

<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="js/disable-right-click.js"></script>

JavaScript(disable-right-click.js)では、contextmenuイベントハンドラ内で、event.preventDefaultを実行することで、ウェブブラウザの標準動作(この例ではコンテキストメニューの表示)を停止している。

// disable-right-click.js

'use strict';

$(function () {

  $(document).on('contextmenu', function (event) {
    event.preventDefault();
  });

});

5.6. 画面要素間の連動

5.6.1. 概要

画面要素間の連動とは、ある画面要素において、指定されたイベントを検知し、別の画面要素を変更することである。

ここでは、jQueryを用いた画面要素の連動の方法について説明する。

例として、地域区分のドロップダウンリストと都道府県のドロップダウンリストが連動するサンプルを用いる。

利用ライブラリ サンプル 参考ページ
jQuery -

5.6.2. 利用方法

HTMLでは、jQueryと、画面要素間の連動を制御するために実装したJavaScript(work-with-element.js)を読み込む。

連動させる要素である地域区分と都道府県のドロップダウンリストにはidを設定する。

<h3>地域区分:</h3>
<select id="region">
  <option>-- 地域区分 --</option>
  <option value="hokkaido">北海道</option>
  <option value="tohoku">東北</option>
  <option value="kanto">関東</option>
  <option value="chubu">中部</option>
  <option value="kinki">近畿</option>
  <option value="chugoku">中国</option>
  <option value="shikoku">四国</option>
  <option value="kyushu">九州・沖縄</option>
</select>
<br>
<h3>都道府県:</h3>
<select id="prefecture">
  <option>-- 都道府県 --</option>
</select>

<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="js/work-with-element.js"></script>

JavaScript(work-with-element.js)では、onメソッドを使って地域区分ドロップダウンリストにchangeイベントが発生した際に実行する関数を設定する。

設定した関数の中で、選択された地域区分の情報をキーに都道府県リストを取得し、そのリストを都道府県ドロップダウンリストに追加する。

// work-with-element.js

'use strict';

$(function () {

  // (1)
  var regions = $('#region');
  var prefectures = $('#prefecture');

  // (2)
  regions.on('change', function () {

    // (3)
    var prefecture = prop.data[regions.val()];

    // (4)
    prefectures.empty();

    // (5)
    if (prefecture instanceof Array) {
      for (var i = 0, len = prefecture.length; i < len; i++) {
        var option = $('<option>').text(prefecture[i].text)
                      .val(prefecture[i].value);
        prefectures.append(option);
      }
    }
  });
});

// (6)
var prop = {
  'data' : {
    'hokkaido' : [
      {'text': '道央', 'value': 'douou'},
      {'text': '道北', 'value': 'douhoku'},
      {'text': '道東', 'value': 'doutou'},
      {'text': '道南', 'value': 'dounan'}
    ],

    // 省略

    'kyushu' : [
      {'text': '福岡', 'value': 'fukuoka'},
      {'text': '佐賀', 'value': 'saga'},
      {'text': '長崎', 'value': 'nagasaki'},
      {'text': '熊本', 'value': 'kumamoto'},
      {'text': '大分', 'value': 'oita'},
      {'text': '宮崎', 'value': 'miyazaki'},
      {'text': '鹿児島', 'value': 'kagoshima'},
      {'text': '沖縄', 'value': 'okinawa'}
    ]
  }
};
項番 説明
(1)
連動させる要素を取得する。
(2)
地域区分が選択されたときに実行する関数を定義する。
(3)
選択された地域区分の情報をキーに都道府県リストを取得する。prop.dataには、地域ごとに分けられた都道府県オブジェクトの配列が定義されている。
(4)
都道府県ドロップダウンリストを一旦空にする。
(5)
都道府県ドロップダウンリストに取得した都道府県リストを追加する。
(6)
地域ごとに分けられた都道府県オブジェクトの配列。

5.6.3. 応用方法

画面要素間の連動を実現する際は、リストをJavaScriptファイルにハードコーディングするのではなく、サーバもしくは外部ファイルに持たせて取得するケースが考えられる。

ここでは、非同期通信で取得したリストを画面要素に反映する方法を紹介する。以下に例を示す。

HTMLは同様のため割愛する。(ただし、本サンプルでは非同期通信失敗時の挙動も確認できるよう、「非同期通信挙動選択」のラジオボタンを配置している。)

  • JavaScript
// work-with-element-ajax.js

'use strict';

$(function () {

  var regions = $('#region');
  var prefectures = $('#prefecture');

  regions.on('change', function () {

    // (1)
    var callback =  function (data) {

      var prefecture = data[regions.val()];
      prefectures.empty();
      if (prefecture instanceof Array) {
        for (var i = 0, len = prefecture.length; i < len; i++) {
          var option = $('<option>').text(prefecture[i].text)
                        .val(prefecture[i].value);
          prefectures.append(option);
        }
      }
    };

    // (2)
    $.ajax({
      'type' : 'GET',
      'url' : url,
      'dataType' : 'json'
    })
    .then(callback)
    .catch(function() {
      $('#message-area').append('<p>エラー発生 : 通信に失敗しました。</p>');
      prefectures.empty();
    });
  });
});
項番 説明
(1)
選択された地域区分の情報をキーに都道府県リストを設定する関数。引数dataには非同期通信で取得した都道府県リストを受け取る。
(2)
非同期通信を実行する。非同期通信成功後にthenのコールバックを実行する。

上記のサンプルのように、ajaxを利用することでJavaScriptファイルにハードコーディングせず、非同期通信でリストを取得し画面要素に反映できる。ajaxの詳細な利用方法については Ajaxを利用した連携 を参照すること。

上記では省略しているが、本サンプルでは非同期通信失敗後の挙動も確認できるよう実装しているので参考にしてほしい。

5.7. フォーマット変換・文字種変換

5.7.1. 概要

本節で紹介するフォーマット変換・文字種変換とは、ユーザーが入力した入力値のフォーマットや文字種を自動的に変換することを指す。
ここでは、フォーマット変換・文字種変換について、日付を操作するMoment.jsと独自に実装したJavaScriptを用いて実現する方法を紹介する。
利用ライブラリ サンプル 参考ページ
Moment.js
- 特定文字の全角半角変換 -

5.7.2. 利用方法

5.7.2.1. 日付フォーマット変換

ここではMoment.jsを使用して日付フォーマットを変換する方法を紹介する。
サンプルは、日付入力欄のフォーカス時に「YYYYMMDD」形式に変換し、フォーカスアウト時に「YYYY/MM/DD」形式に変換する。
HTMLでは、jQuery、Moment.jsと独自に実装したJavaScript(convert-date.js)を読み込む。
<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="../lib/vendor/moment/2.22.2/moment.min.js"></script>
<script src="js/check-date.js"></script>
JavaScript(convert-date.js)では、以下のように処理を実装する。
// convert-date.js

'use strict';

$(function () {
  $('#date').on({

    // (1)
    'focus' : function () {
      var date = $('#date').val();
      if (date === '') {
        return;
      }

      // (2)
      $('#date').val(moment(date, 'YYYY/MM/DD', true).format('YYYYMMDD'));
    },

    // (3)
    'blur' : function () {
      var date = $('#date').val();
      if (date === '' || moment(date, 'YYYY/MM/DD', true).isValid()) {
        return;
      }

      // (4)
      $('#date').val(moment(date, 'YYYYMMDD', true).format('YYYY/MM/DD'));
    }
  });
});
項番 説明
(1)
フォーカス時に発生するイベントを定義する。
(2)
スラッシュなしのフォーマットに変換する。
(3)
フォーカスアウト時に発生するイベントを定義する。
(4)
スラッシュありのフォーマットに変換する。
momentメソッドの第1引数に日付(文字列)、第2引数にフォーマットを設定すると、フォーマットに従ってパースする。formatメソッドにフォーマットを設定すると、指定したフォーマットに変換した日付を取得できる。

Note

momentの第3引数にtrueを設定すると、Strictモードで動作する。Strictモードは、入力値がフォーマットと一致していることを厳密にチェックし、一致する場合のみ有効な日付としてパースする。

第3引数を省略、またはfalseを設定した場合、Forgivingモードで動作する。Forgivingモードは、入力値がフォーマットとある程度異なっても有効な日付としてパースする。

各モードの挙動の差異について、以下に例を示す。

// (1)
// (1-a)
moment('2015-01-01', 'YYYY/MM/DD', false).format('YYYYMMDD');

// (1-b)
moment('2015-01-01', 'YYYY/MM/DD', true).format('YYYYMMDD');

// (2)
// (2-a)
moment('2015/01/31 is Date', 'YYYY/MM/DD', false).format('YYYYMMDD');

// (2-b)
moment('2015/01/31 is Date', 'YYYY/MM/DD', true).format('YYYYMMDD');
項番 説明
(1)
入力値(2015-01-01)とフォーマット(YYYY/MM/DD)が異なる場合。
(1-a)
Forgivingモードの場合では返却値が20150101となる。
(1-b)
StrictモードではInvalid dateとなる。
(2)
入力値(2015/01/31 is Date)に日付以外が含まれる場合。
(2-a)
Forgivingモードの場合では返却値が20150131となる。
(2-b)
StrictモードではInvalid dateとなる。

また、Forgivingモードはフォーマットを厳密にチェックしないため、入力値が誤って変換される可能性がある。

// (1)
moment('01/12/2016', 'YYYY/MM/DD', false).format('YYYYMMDD');
項番 説明
(1)
入力値(01/12/2016)とフォーマット(YYYY/MM/DD)が異なるが、Forgivingモードでは20011220として解釈される。

このように、Forgivingモードは故障に繋がる可能性があるため、Strictモードを利用することを推奨する。

Warning

入力値に誤りがある場合、入力欄に「Invalid date」が出力される。メッセージの文言や出力位置は変更できないため、入力値の妥当性を事前にチェックし、エラーの場合はメッセージを出力するよう実装すること。チェック方法は日付妥当性チェックに記述する。

5.7.2.2. 日付妥当性チェック

ここでは、Moment.jsを使用して日付の妥当性をチェックする方法を紹介する。
本節の妥当性チェックは、入力値のフォーマットが正しいこと、日付が実在することを判定する。許容するフォーマットは指定できる。
HTMLでは、jQuery、Moment.jsと独自に実装したJavaScript(check-date.js)を読み込む。
<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="../lib/vendor/moment/2.22.2/moment.min.js"></script>
<script src="js/check-date.js"></script>
JavaScript(check-date.js)では、日付の入力欄にblurイベントが発生した際、入力値の妥当性をチェックする。
momentメソッドの引数に、入力値、フォーマットとStrictモードで実行するためのtrueを設定し、isValidメソッドを実行する。
// check-date.js

'use strict';

$(function () {
  $('#date').on({

    // (1)
    'blur' : function () {
      var date = $('#date').val();

      // (2)
      var result = moment(date, 'YYYY/MM/DD', true).isValid();

      $('#date-area > span').remove();
      if (result) {
        $('#date-area').append('<span>入力値は正常です。</span>');
      } else {
        $('#date-area').append('<span>入力値に誤りがあります。</span>');
      }
    }
  });
});
項番 説明
(1)
フォーカスアウト時に発生するイベントを定義する。
(2)
入力値の妥当性をチェックする。
momentメソッドは、日付をパースする際、フォーマットに合致していること、日付が実在することをチェックする。isValidメソッドを実行すると、チェック結果を確認できる。パースに成功した場合はtrue、失敗した場合はfalseが返却される。

Note

複数のフォーマットを許容する場合、以下のように配列を設定すればよい。

var result = moment(date, ['YYYY/MM/DD','YYYYMMDD'], true).isValid();

Note

日付フォーマット変換のサンプルに本節の妥当性チェックを組み合わせた実装例を以下に示す。

// (1)
'blur' : function () {
  var date = $('#date').val();

  // (2)
  var result = moment(date, 'YYYYMMDD', true).isValid();

  if (!result) {
    $('#form-area').append('<span>入力値に誤りがあります。</span>');
    return false;
  }

  // (3)
  $('#date').val(moment(date, 'YYYYMMDD', true).format('YYYY/MM/DD'));
}
項番 説明
(1)
フォーカスアウト時に発生するイベントを定義する。
(2)
入力値の妥当性をチェックする。
(3)
スラッシュありのフォーマットに変換する。

5.7.2.3. 時刻フォーマット変換

ここではMoment.jsを使用して時刻フォーマットを変換する方法を紹介する。
サンプルは、時刻入力欄のフォーカス時に「HHmmss」形式に変換し、フォーカスアウト時に「HH:mm:ss」形式に変換する。
HTMLでは、jQuery、Moment.jsと独自に実装したJavaScript(convert-time.js)を読み込む。
<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="../lib/vendor/moment/2.22.2/moment.min.js"></script>
<script src="js/convert-time.js"></script>
JavaScript(convert-time.js)では、以下のように実装する。
// convert-time.js

'use strict';

$(function () {
  $('#time').on({

    // (1)
    'focus' : function () {
      var time = $('#time').val();
      if (time === '') {
        return;
      }

      // (2)
      $('#time').val(moment(time, 'HH:mm:ss', true).format('HHmmss'));
    },

    // (3)
    'blur' : function () {
      var time = $('#time').val();
      if (time === '' || moment(time, 'HH:mm:ss', true).isValid()) {
        return;
      }

      // (4)
      $('#time').val(moment(time, 'HHmmss', true).format('HH:mm:ss'));
    }
  });
});
項番 説明
(1)
フォーカス時に発生するイベントを定義する。
(2)
コロンなしのフォーマットに変換する。
(3)
フォーカスアウト時に発生するイベントを定義する。
(4)
コロンありのフォーマットに変換する。
momentメソッドの第1引数に時刻(文字列)、第2引数にフォーマットを設定すると、フォーマットに従ってパースする。formatメソッドにフォーマットを設定すると、指定したフォーマットに変換した時刻を取得できる。

Warning

momentのパラメーターに不正な値を設定した場合、入力欄に「Invalid date」や想定外の値が出力される。入力値の妥当性を事前にチェックし、エラーの場合はメッセージを出力するよう実装すること。日付妥当性チェックと同様の方法でチェックできる。

5.7.2.4. 特定文字の全角半角変換

ここでは、JavaScriptを使用して、特定文字(「英字」、「数字」や一部の「記号」)を全角文字・半角文字に相互変換する実装例を紹介する。
HTMLでは、jQueryと独自に実装したJavaScript(convert-zenkaku-hankaku.js)を読み込む。
<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="js/convert-zenkaku-hankaku.js"></script>
JavaScript(convert-zenkaku-hankaku.js)では、入力欄にblurイベントが発生した際、独自に実装したconvertStyle関数を実行する。コードを区切って説明する。
まずstyleオブジェクトに変換対象の全角文字・半角文字を定義する。
var style = {
  'zenkaku' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 (){}[]<>=+‐-*/|_?,.¥@^;:!#$%&',
  'hankaku' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 (){}[]<>=+--*/|_?,.\\@^;:!#$%&'
};
convertStyle関数は、inputの文字数分ループする。
入力値の文字がfromStyleに格納された文字に該当する場合、toStyleの文字に置換する。
// (1)
var convertStyle = function (input, type) {
  var fromStyle;
  var toStyle;
  var output = [];

  switch (type) {
    case 'zenkaku':

      // (2)
      fromStyle = style['hankaku'];

      // (3)
      toStyle = style['zenkaku'];
      break;
    default:

      // (4)
      fromStyle = style['zenkaku'];

      // (5)
      toStyle = style['hankaku'];
      break;
  }

  var pos;
  for (var i = 0, len = input.length; i < len; i++) {

    // (6)
    pos = fromStyle.indexOf(input.charAt(i));
    if (pos < 0) {

      // (7)
      output[i] = input.charAt(i);
    } else {

      // (8)
      output[i] = toStyle.charAt(pos);
    }
  }
  return output.join('');
};
項番 説明
(1)
特定文字の全角半角変換用の関数を定義する。
第1引数に変換対象の文字列を指定し、第2引数に変換形式(半角から全角に変換する場合は「zenkaku」、全角から半角に変換する場合は「hankaku」)を指定する。
(2)
typeが「zenkaku」の場合、変換前の文字列に半角文字列を格納する。
(3)
変換後の文字列に全角文字列を格納する。
(4)
typeが「hankaku」の場合、変換前の文字列に全角文字列を格納する。
(5)
変換後の文字列に半角文字列を格納する。
(6)
入力値の位置を取得する。
(7)
該当しない場合、入力値を格納する。
(8)
該当する場合、’toStyle’の文字を格納する。
入力欄にblurイベントが発生した際、convertStyle関数を呼び出す。第2引数に変換後の文字種(「zenkaku」・「hankaku」)を指定する。
  $('#zenkaku-string').on({

    // (9)
    'blur' : function () {

      var st = $('#zenkaku-string').val();

      // (10)
      $('#zenkaku-string').val(convertStyle(st, 'zenkaku'));
    }
  });

  $('#hankaku-string').on({
    'blur' : function () {

      var st = $('#hankaku-string').val();

      // (11)
      $('#hankaku-string').val(convertStyle(st, 'hankaku'));
    }
  });
});
項番 説明
(9)
フォーカスアウト時に発生するイベントを定義する。
(10)
半角文字を全角に変換する。
(11)
全角文字を半角に変換する。

Note

本実装例は、styleオブジェクトのzenkakuとhankakuに、変換対象の文字が対になるように定義する。変換時は対象文字の定義位置を取得し、相対する文字種から同じ位置に定義されている文字を取得することで変換処理を実現している。

実装例のstyleオブジェクトにない文字を変換したい場合、styleオブジェクトの定義内容を変更すればよいが、定義する文字や順序に誤りが無いよう注意すること。

Note

「英字」を大文字、または小文字のみに変換する場合、JavaScriptのtoUpperCasetoLowerCaseで入力値を変換すればよい。

5.8. 入力値チェック

5.8.1. 概要

ここでは、Parsleyを用いた入力値チェックの実装方法を説明する。
Parsleyはクライアントサイドでの入力値チェックを容易に実現するためのライブラリである。
利用ライブラリ サンプル 参考ページ
Parsley Parsley - The ultimate documentation

Note

クライアントサイドでの入力値チェックは、入力値が受け付けられるかどうかをサーバにリクエストすることなく即座に確認できるため、ユーザビリティの向上に寄与する。

ただし、クライアントから送信されるパラメータは容易に改ざんできるため、サーバサイドでの入力値チェックの代替にはならない。業務上のデータ不整合を防ぐためには必ずサーバサイドでのチェックを実施すること。

5.8.2. 利用方法

5.8.2.1. 基本的な使用方法

HTMLでは、次の順番でJavaScriptを読み込む。

  1. jQuery
  2. Parsley本体
  3. Parsley拡張プラグイン (日付形式検証などの、拡張プラグインとして提供されている機能を使用する場合のみ)
  4. Parsleyメッセージ定義ファイル (指定しない場合メッセージは英語で出力される。)
  5. 独自実装したJavaScript
<script src="../lib/vendor/jquery/3.3.1/jquery.min.js"></script>
<script src="../lib/vendor/parsleyjs/2.8.1/parsley.min.js"></script>
<script src="../lib/vendor/parsleyjs/2.8.1/extra/validator/dateiso.js"></script>
<script src="../lib/vendor/parsleyjs/2.8.1/i18n/ja.js"></script>
<script src="js/validation.js"></script>

検証ルールを適用するためには、対象のinputに対してdata-parsley-検証ルール名という属性を指定する。次の例は、年齢フィールドが「入力必須」「正の整数値」「20以上」であることを検証する例である。

<label for="age">年齢</label><br>
<input id="age" name="age" type="text"
       data-parsley-type="digits"
       data-parsley-min="20" data-parsley-min-message="未成年は登録できません。">

検証エラー時のメッセージは、エラーとなった検証ルールのデフォルトメッセージが表示される ( 設定方法は デフォルトエラーメッセージ定義と国際化対応 を参照) 。ただし、上の例にあるdata-parsley-min-message="未成年は登録できません。"のように、検証ルール属性-message属性を用いることで、特定の検証ルールのみメッセージを変更できる。

その他の検証ルールとして、以下が使用できる。

属性 用途
data-parsley-required="true" 入力必須であることを検証する。
data-parsley-type="digits" 正の整数値であることを検証する。
data-parsley-type="email" Eメール形式であることを検証する。
data-parsley-min="n"
(n は正の整数)
n 以上の数値であることを検証する。
data-parsley-max="n"
(n は正の整数)
n 以下の数値であることを検証する。
data-parsley-length="[m, n]"
(m, n は正の整数)
m 文字以上 n 文字以下であることを検証する。
data-parsley-equalto="セレクタ文字列" セレクタで指定した要素の値と同じ値であることを検証する。

検証ルールの完全な一覧は Validators list を参照すること。

JavaScript(validation.js)では、 入力値チェック対象となるフォーム要素をjQueryでセレクトし、parsleyメソッドを実行する。

parsleyメソッドの引数には、次のようにオプションを指定するためのオブジェクトを指定できる。

// validation.js

'use strict';

$(function () {

  // (1)
  $('#form').parsley({

    // (2)
    inputs: 'input, textarea, select',

    // (3)
    excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',

    // (4)
    errorClass: 'has-error',

    // (5)
    successClass: '',

    // (6)
    classHandler: function (ParsleyField) {

      // (7)
      return ParsleyField.$element.parent();
    },

    // (8)
    errorsContainer: function (ParsleyField) {

      // (9)
    },

    // (10)
    errorsWrapper: '<ul class="parsley-errors-list"></ul>',

    // (11)
    errorTemplate: '<li></li>'
  });

});
項番 説明
(1)
バリデーションを有効化する。
(2)
検証対象の要素を指定する。(セレクタ文字列、またはjQueryオブジェクト)
(3)
検証対象から除外する要素を指定する。(セレクタ文字列、またはjQueryオブジェクト)
(4)
検証エラー時に付与するクラス名を指定する。
(5)
検証成功時に付与するクラス名を指定する。
(6)
検証結果に応じてクラスを付与する要素を指定する。(セレクタ文字列、jQueryオブジェクト、またはそれらを返す関数)
(7)
検証エラーが起きた input要素の親要素にhas-errorクラスを付与する。
(8)
エラーメッセージを追加する要素を指定する。(文字列、jQueryオブジェクト、またはそれらを返す関数)
(9)
エラーメッセージの表示位置を指定する。実装しない場合(オプション未指定時)やundefinedを返すと、input要素の次に作られる。
(10)
エラーメッセージの親要素に用いるHTML文字列を指定する。
(11)
エラーメッセージ表示に用いるHTML文字列を指定する。

これらのオプションを使用することで、エラー時のメッセージ表示位置やスタイルの変更などを柔軟にカスタマイズすることができる。

5.8.2.2. デフォルトエラーメッセージ定義と国際化対応

Parsleyの出力するデフォルトのエラーメッセージは英語であるが、他の各言語についてもデフォルトのエラーメッセージ定義が提供されている (i18nディレクトリ配下)。また、それらのファイル内のメッセージ定義を任意の内容に書き換えることができる。日本語のメッセージを変更する場合は、i18n/ja.js に定義されているメッセージ部分を直接書き換えればよい。

デフォルトのエラーメッセージを変更したい場合は、次のように Parsley 本体の後に読み込む。

<script src="jquery.js"></script>
<script src="parsley.min.js"></script>
<script src="i18n/ja.js"></script>

複数のロケールに対応する場合には、次のように複数の言語のメッセージ定義を読み込んだ後、Parsley.setLocaleメソッドを用いて適用するロケールを指定する。

<script src="jquery.js"></script>
<script src="parsley.min.js"></script>
<script src="i18n/fr.js"></script>
<script src="i18n/ja.js"></script>
<script type="text/javascript">
  var locale = (navigator.language || navigator.userLanguage).substring(0, 2);
  try {
    window.Parsley.setLocale(locale);
  } catch (e) {
    window.Parsley.setLocale('en');
  }
</script>

この例は、Parsley.setLocaleメソッドで指定するロケールをウェブブラウザの設定言語から取得して適用する例である。 この例では ‘en’, ‘fr’, ‘ja’ が有効となり、ウェブブラウザから取得したロケールから選択される。

5.8.2.3. カスタムバリデータの実装方法

独自の検証ルールとメッセージを追加するためには、Parsley本体の読み込み後に、Parsley.addValidatorメソッドを使用する。

次の例は、指定した数値の倍数であることを検証する独自の検証ルール multipleof の実装および使用例である。

HTMLでは以下のようなinput要素を設置する。

<input type="text" data-parsley-multipleof="3">

独自の検証ルール名 multipleof に合わせた data-parsley-multipleof 属性に値を指定する。

Javascriptでは以下のように実装する。

// (1)
Parsley.addValidator('multipleof', {

  // (2)
  requirementType: 'number',

  // (3)
  validateNumber: function (value, requirement) {
    return 0 === value % requirement;
  },

  // (4)
  messages: {
    en: 'This value should be a multiple of %s',
    ja: '%s の倍数である必要があります。'
  }
});
項番 説明
(1)
第1引数に検証ルール名、第2引数に検証ルールのオブジェクトを指定したaddValidatorメソッドを使用する。
(2)
要求パラメータの型。カスタムバリデータが期待している要求パラメータ(上記例ではdata-parsley-multipleof="3")の型を指定する。 stringintegernumberdateregexpbooleanが用意されており、これらの配列も利用できる。
(3)
検証を実行する関数で、入力値が期待する型に合わせて、validateStringvalidateNumbervalidateDatevalidateMultipleの中から少なくとも1つを指定する必要がある。 2つの引数として、対象のinput要素の値と、オプション (data-parsley-multipleof="3"のように使用した場合は3) を受け取る。成功時はtrue、失敗時はfalseを返すように実装する。
(4)
検証エラー時に表示されるメッセージを設定する。 keyにロケール、valueにメッセージ本文となるObjectとなるよう設定する。メッセージ本文には%sプレースホルダを用いることでオプション値を埋め込むことができる。

Note

より高度な入力値チェックの例として、サーバ通信を伴う入力値チェックがある。具体例の一つとして、ユーザ登録フォームの「ユーザID」が利用可能かどうかを検証するためサーバに問い合わせるといったケースが考えられる。

このような機能も、カスタムバリデータを実装することで実現できる。

Parsley.addValidator('registerable', {
  requirementType: 'string',

  // (1)
  validateString: function (value) {
    var status = $.ajax({
      url: '/userid_available',

      // (2)
      data: 'id=' + value,

      // (3)
      async: false
    }).status;

    // (4)
    return status !== 409;
  },
  messages: {
    en: 'this USER ID is already used'
  }
});
項番 説明
(1)
登録可能なユーザIDかどうかを検証する関数を定義する。
(2)
パラメータ名をidとし、入力値を設定する。
(3)
asyncオプションにfalseを設定し同期処理とする。
(4)
ステータスコード 409 (Conflict) の場合は登録不可

検証を実行する関数内で結果を返却するため、$.ajaxasyncオプションをfalseにすることで同期的に処理する必要がある。

なお、非同期で検証を行えるカスタムバリデータを作成する専用APIとして、Parsley.addAsyncValidatorメソッドがある (参考)。 ただし、これを用いると、検証時に送信されるパラメータが name属性値=value で固定化され、変形することができない (上のサンプルコード中の data: 'id=' + value のように、パラメータ名を”id”に固定するといったことができない)。

よって、サーバのAPI仕様に合わせてパラメータを変形する必要がある場合はParsley.addValidatorメソッドを、必要ない場合はParsley.addAsyncValidatorメソッドを用いるとよい。