実践ServiceNow：開始日と終了日フィールドがあるフォームの作成

#概要
ServiceNowの機能を説明するドキュメントはありますが、実際に最初から最後まで日本語フォームを作成する手順が書かれた記事は少ないです。特に日本語の記事は少ない。
それで本記事ではServiceNowで実際に日本語のフォームを開発する手順を書きます。
多くのフォームで使われる開始日フィールドと終了日フィールドの実装の仕方を例としてServiceNowでフォームを作成するために使える基本機能と操作手順の説明を含めます。
作成するのは次のように開始日と終了日だけのフォームですが、次の入力チェックを行います。また、メッセージの日本語と英語での切り替えにも対応します。
チェック項目：
・開始日は今日以降の日付である
・終了日は開始日以降の日付である
![sample_screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/c5be4cf7-8910-68ee-b479-914e386ed713.png)


##１．アイテムの作成
先ずは入力フォームを作成します。
①ServiceNowの左側にあるアプリケーションナビゲータから「アイテムの管理」を検索して開きます。
![maintain_item_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/eed16971-916b-8dfb-e352-dbe2eaab8555.png)
②「新規」ボタンを押下。ServiceNowでは新規に要素を作成する場合は新規ボタンを押下します。
![maintain_item_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/caee0846-5a2e-18ee-8cef-f25a59270685.png)
③項目「名前」にフォームの名前を入力します。フォーム一覧に表示する名前になります。システム内部ではsys_idと言う連番で管理されるので既にあるフォームと同じ名前にすることもできますが、探すのに時間が掛かるようになりますので出来る限りユニークな名前をつけることを推奨します。
これで空のフォームは作成されます。フォームに入力フィールドを追加するには一旦保存する必要があります。
保存するには右上の「更新」ボタンを押下することもできますが、一覧画面に戻るので、再び作成したフォームを開く必要があります。
移動せずに保存する場合は上のグレーの部分を右クリックして「保存」を選択します。保存されるとページの下に「変数」などを追加するためのタブが表示されます。
![maintain_item_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/8ca6b1ed-f1f3-a2f5-ca3e-3e6b3d260ba4.png)

##２．変数の追加
フォームに入力フィールドを追加します。ServiceNowでは入力フィールドを「変数」と呼びます。
①フォームを作成するとページの下の複数のタブが表示されます。フィールドを追加するには「変数」タブを選択して、「新規」ボタンを押下します。
![variables_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/4216e85b-404b-36c1-dbad-f476e186766e.png)
②フィールドの属性を指定します。日付を入力するのでタイプは「日付」にします。
項目「順番」はフォームで表示する順です。ServiceNowではフォームのレイアウトはServiceNowが動的に決めます。項目「順番」はフィールドを配置する順番です。上昇順に表示されます。特に指定する数字の決まりはありませんが、後からフィールドを追加できるように数字を開けてつけることを推奨します。
項目「質問」をフィールドの左に表示されるラベルです。
項目「名前」は内部で使うIDです。スクリプトではこのIDを指定してフィールドの操作を行います。基本的にはすべて小文字で単語をアンダースコア「_」で区切ります。英語モードでは質問を入力すると名前は自動的に入力されます。
![variables_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/eec6b5b0-5be1-adac-af4a-be8cd4321d78.png)
③デフォルトに今日の日付を設定するには「デフォルト」タブを選択に「デフォルト値」に「now」を入力います。
![variables_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/4ac3a660-ab0c-3de4-7a57-0134dd02c871.png)
④設定したフィールドを保存するために右上の「更新」ボタンを押下します。フォーム設定画面に戻ります。
⑤同じような操作で終了日フィールドも追加します。終了日は開始日の下に配置するので「順番」に開始日よりも大きな数字を指定します。
![variables_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/2452eaa7-518d-4766-8506-8b32b48c453c.png)
⑥終了日もデフォルトを今日にします。開始日と同じように「デフォルト」タブを選択して「デフォルト値」に「now」を入力います。
⑦設定したフィールドを保存するために右上の「更新」ボタンを押下します。フォーム設定画面に戻ります。

##３．UIポリシーの設定
ServiceNowでは出来る限りコーディング無しでフォームを作成することを推奨しています。
開始日が今日以降の日付であるチェックはUIポリシーで設定できます。
①フォーム設定ページの下にあるタブ集の中から「カタログUIポリシー」を選択して、「新規」ボタンを押下します。
![ui_policy_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/681d0486-939c-106f-0d14-f8e2a3338bea.png)
②「＊」が付いている項目は必須項目です。このページでは項目「カタログアイテム」と項目「簡単な説明」が必須です。
項目「カタログアイテム」は自動的に入力されているので変更せずでOKです。
項目「簡単な説明」はUIポリシーの名前になります。適当な名前を入力します。下の画面では「Start Daate if today or after」を入力しています。
次にこのUIポリシーを実行する条件を指定します。
開始日が今日以降で無い場合はエラーメッセージを表示させます。
開始日が今日以降であることを条件にするためには「適用時期」タブを選択して、「start_date」、「次の前」、「今日」と指定します。「start_date」は開始日を作成するときに指定したフィールドの「名前」です。
![ui_policy_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/5768d3ba-75f3-703f-1547-415bcf23266a.png)
③残念ながらまだコードなしでエラーメッセージは表示できません。ここではJavaScriptを利用してエラーメッセージを表示します。
「スクリプト」タブを選択して、「スクリプトの実行」をチェックすると「Trueの場合実行」に「function onCondition() {}」が入力されます。「{}」の間に次のようにコードを入力します。
「g_form」はServiceNowのフォームオブジェy区とです。「showErrorBox("start_date", "Please select today or date later than today")」はエラーメッセージを表示します。

```
function onCondition() {
    g_form.showErrorBox("start_date", "Please select today or date later than today");
}
```
![ui_policy_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/799f4388-4044-fce9-f3bc-78a31d024b57.png)
④これでUIポリシーの設定は終了です。右上の「更新」ボタンを押下して設定を保存してフォーム設定ページに戻ります。

##４．クライアントスクリプトの作成
残念ながらまだUIポリシーで２つのフィールドを比較することはできません。そのため、終了日が開始日以降であることをチェックするにはクライアントスクリプトで行います。
今回は２つのスクリプトを作成します。一つは終了日が開始日の後であることをチェックするスクリプトでもう一つは開始日を終了日より後に日付に変更した場合に終了日を開始日に変更するスクリプトです。
先ずは最初の終了日チェックのスクリプトを作成します。
①クライアントスクリプトを作成する場合はフォーム設定ページの下のタブ集から「カタログクライアントスクリプト」タブを選択して、「新規」ボタンを押下します。
![client_script_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/fa50a68c-0e7b-8c4b-0cf1-b7664e33f59a.png)
②項目「名前」に作成するスクリプトを識別するための名前を入力します。
終了日が変更された場合にチェックを行うようにするために、項目「タイプ」を「onChange」に設定して、項目「変数名」を「end_date」にします。「end_date」は終了日フィールドを作成したときに指定した名前です。
![client_script_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/def71b7d-100a-38d8-370a-c0d1a52262e0.png)
③指定した条件の場合にチェックを実行するために「スクリプト」に次のコードを入力します。
スクリプトは入力された開始日の値を取得してJavaScriptのDateオブジェクトを生成します。「newValue」は入力された値です。この場合は「end_date」の場合に実行されるので終了日の新しい値になります。
if文で開始日が終了日より大きいか確認して、大きい場合はエラーメッセージを表示します。
UIポリシーのスクリプトと類似して、終了日フィールドの下にエラーメッセージを表示します。

```
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue == '') {
        return;
    }
    var startDate = new Date(g_form.getValue('start_date'));
    var endDate = new Date(newValue);
    if (startDate > endDate) {
        g_form.showErrorBox('end_date', 'Please select a date on or later than the start date');
    }

}
```
④記入を終了したら、右上の「更新」ボタンを押下してフォーク設定ページに戻ります。
⑤次の日付に変更した場合に終了日を開始日に変更するスクリプトを作成します。終了日チェック・スクリプトと同じようにフォーム設定ページの「カタログクライアントスクリプト」タブの「新規」ボタンを押下します。
⑥開始日が変更された場合に実行するので項目タイプを「onChange」に指定して、項目「変数名」を「start_date」にします。
⑦次のスクリプトを入力します。
今回はstart_date（開始日）が変更された場合に実行するように指定したので、newValueは開始日の値になります。
また、今回はエラーメッセージを表示するのではなく終了日の開始日に設定するのでg_form.setValue(＜変更するフールド名＞,値)メソッドを使いはす。

```
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue == '') {
        return;
    }
    var startDate = new Date(newValue);
    var curDate = new Date();
    if (startDate < curDate) {
	g_form.hideFieldMsg('start_date');
        g_form.showFieldMsg('start_date', getMessage('Please select a date later than the current date/time'), 'error');
    } else {
        var endDate = new Date(g_form.getValue('end_date'));
        if (startDate > endDate) {
            g_form.setValue('end_date', newValue);
        } else {
            g_form.hideAllFieldMsgs();
        }
    }
}
```
![client_script_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/9234215c-6dae-f1ef-f4e5-3f089fb31542.png)
⑧スクリプトを入力したら右上の「更新」ボタンを押下してフォーム設定ページに戻ります。

##５．画面確認
日本語メッセージを作成する前に今まで設定した内容で正しくフォームが表示できるか確認します。
①右上の「試行」ボタンを押下します。
![try_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/d181b7a6-0dfb-5c47-07a7-43eb4928d516.png)
②次のような画面が表示されます。開始日と終了日を変更して設定したUIポリシーとクライアントスクリプトが正しく動作することを確認します。
![try_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/0328a256-a64d-a1b1-cd21-93ae6586fb3c.png)
③試した後にフォーム設定ページに戻ります。
戻る場合は左上の「＜」アイコンを押下します。但し、Webブラウザの別タブでServiceNowの別ページを表示するとそちらのページに移動します。その場合はServiceNowの履歴機能を利用します。
![try_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/a146c298-a01b-b868-b6e6-f35c37e4d851.png)
④履歴機能を利用するにはフィルターナビゲーターの右下の履歴アイコンを押下します。今まで開いて来たページ一覧が表示されます。そこから「カタログアイテムStart and End Dates」を選択するとフォーム設定ページに戻ります。
![try_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/66132dec-27b0-eb1b-4f7a-0773c1b26069.png)

##６．日本語メッセージの作成
動作が正しいことを確認できたら、日本語でメッセージが表示されるようにします。
①アプリケーションナビゲータから「メッセージ」を検索します。「システムUI」下の「メッセージ」を選択します。
![message_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/4215149e-db8c-687e-3b9a-5c15261d369e.png)
ServiceNowに慣れてくると毎回アプリケーションナビゲータから検索するよりも直接ページを開くことができます。メッセージ一覧はテーベいる「sys_ui_message」を表示しているので「sys_ui_message.list」を入力するとメッセージ一覧が表示します。「.list」はテーブルの内容を一覧表示すると言う意味です。ServiceNowの他のテーブルも「＜テーブル名＞.list」で表示します。
![message_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/dc4bafdc-2a56-bbf3-bad5-54816dbbf902.png)
②新規にメッセージを作成するので「新規」ボタンを押下します。
③項目「キー」はUIプリシー及びクライアントスクリプトに記述してスクリプトのメッセージです。先ずはUIポリシーのメッセージ「Please select a date on or later than the start date」を入力します。項目「言語」は先ず英語メッセージを作成するので「English」にします。
![message_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/56eeffc9-4f76-0db0-9016-8eb065a69c0d.png)
④英語メッセージを保存します。ただし、日本語メッセージも作成する必要があるので、画面が戻らないようにするために上のグレーのヘッダー領域を右クリックして「保存」を選択します。
![message_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/137d0586-f791-f4d5-f267-b89d03a1b0f8.png)
⑤日本メッセージように項目を修正します。項目言語を「日本語」に指定して日本語メッセージは項目「メッセージ」に入力します。
変更した後に再びグレーのヘッダ領域を右クリックして「挿入」を選択します。「保存」を選択すると英語メッセージが上書きされますので注意してください。
![message_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/7277a933-bf53-faf9-5f45-9440d8525bd4.png)
⑥同じようにクライアントスクリプトに記述した「Please select a date on or later than the start date」の英語と日本語のメッセージを作成します。
⑦最後のメッセージを作成した後に再びフォーム設定ページに戻ります。
アプリケーションナビゲータから「アイテムの管理」を選択して一覧から「Start and End Dates」を選択するか、履歴から「カタログアイテムStart and End Dates」を選択します。
⑧作成したメッセージを利用するようにUIポリシーのスクリプト及びクライアントスクリプトを修正します。
メッセージを利用するにはgetMessage(＜メッセージキー＞)メッソッドを利用します。
先ずはUIポリシースクリプトを修正します。「カタログUIポリシー」タブを選択して「Start Date if today or after」をクリックします。「スクリプト」タブを選択して次のように修正します。

```
function onCondition() {
    g_form.showErrorBox("start_date", getMessage("Please select today or date later than today"));
}
```
![ui_policy_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/050522dd-3ed1-79d9-7d33-945ab88819c3.png)
⑨同じようにクライアントスクリプトを次のように修正します。

```
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue == '') {
        return;
    }
    var startDate = new Date(g_form.getValue('start_date'));
    var endDate = new Date(newValue);
    if (startDate > endDate) {
        g_form.hideFieldMsg('end_date');
        g_form.showFieldMsg('end_date', getMessage('Please select a date on or later than the start date'), 'error');
    } else {
	var curDate = new Date();
        if (startDate < curDate) {
	    g_form.hideFieldMsg('start_date');
            g_form.showFieldMsg('start_date', getMessage('Please select a date later than the current date/time'), 'error');
        } else {
            g_form.hideAllFieldMsgs();
        }
    }
}
```
これでフォームの作成は終了です。

##７．実行
エラーメッセージが日本語で表示されることを確認します。
①フォーム設定ページから再び「試行」ボタンを押下します。
②開始日を今日より前に日に変更すると次のように日本語メッセージが表示されることを確認します。
![final_test_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/a2aec220-30b8-9070-dbbd-d7e7e13ea4cc.png)
③終了日を開始日より前の日付を指定すると次のようんい日本語メッセージが表示されることを確認します。
![final_test_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/33d2a6ba-9819-0915-65c2-c81d11abd2d9.png)