概要
ServiceNowには、フォームやリスト上にボタン、リンク、コンテキストメニューの項目といったUI要素を追加する【UIアクション】と呼ばれる機能が存在する。UIアクションでは、スクリプトを記述し、NowPlatform上でさまざまな処理を実行できるが、基本的にレコードに対して更新を行うため、サーバサイドで実行するのがデフォルトになっている。クライアントサイドで実行する場合は、「クライアント」チェックボックスにチェックを入れることで、クライアントサイドで実行できる。
では、両サイドの実行を行いたい場合はどうすればよいのか?
本記事では、それを行うのにどのような実装が必要か説明する。
事例
例えば、インシデントテーブルのレコードのステータスを"処理中"から"解決済み"に変更するのにUIアクションを用いるとする。しかし、”解決済み”にするには何かしらの解決情報を「コメント」フィールドに入れる必要があるとする。この場合、「コメント」は必須設定にしなければならないが、常時必須にする必要はない。つまりUIアクションを実行したタイミングで「コメント」を検証する必要がある。この検証はクライアントサイドで行う必要があるが、レコードの値の更新はサーバサイドで行う必要がある。
そこで、UIボタンをクリック時に「コメント」フィールドに記入があるかを検証し、無ければエラーメッセージを出し、記入がある場合は、ステータスを遷移させる。
この記事でできること
- 同一のUIアクションでクライアント、サーバサイドの両方の処理を実行できる。
環境、使用する物
- Version : Orland
- 使用言語 : 日本語
- UIアクション
解説
UIアクションについて
- アクセス方法
- UIアクションを作成したいフォームにを開く
- フォームコンテキストメニューから[構成]>[UIアクション]を選択
- [新規]ボタンを押下する。
- 使用するフィールド
今回は事例同様のボタンをフォーム上に作成する。
使用するフィールドは主に以下の6つ。
フィールド名 | 説明 |
---|---|
アクション名 | 現在作成しているUIアクションをスクリプト等で使用する場合の名称を定義する。 |
クライアント | チェックすることで、クライアントサイドで動作する。 |
フォームボタン | フォーム上に現在作成しているUIアクションが動作するボタンを配置する。 |
クリック時 | "クライアント"をチェックすると表示される。ボタン、リンク等のクリック時に動作する関数を定義する。 |
条件 | UIアクションが表示される条件を定義する。 |
スクリプト | JavaScriptで動作するスクリプトを記述する。 |
- 使用するAPI・構文の解説
今回使用する重要なAPIと構文は2つである。
gsftSubmit(null, g_form.getFormElement(), '<action_name>');
gsftSubmit()は、UIアクション内で使用され、クライアントサイドの処理が正常に終了した場合に、サーバサイドの処理を実行するAPI。
第2引数で現在のフォーム要素の全てを取得し、第3引数で取得した要素の中から定義したアクション名と同一なUIアクションをサーバサイドで実行するといったニュアンスである。
というのも、ServiceNow内ではデフォルトで使用されているAPIでありながら、残念ながらこれを説明する公式ドキュメンは存在していないため正確な情報が今のところ存在していない、しかしこのAPIに言及するコミュニティの回答は多く見られる1 2 3。
if(typeof window == 'undefined')
server_Side_function();
こちらはサーバサイドの処理を実行する前に、スクリプトがWebブラウザ内のWebページで実行されているかどうかを確認する構文。
window型が未定義ならば処理を実行することで、サーバサイドの処理が正常に行える状態かをチェックしている。
実践!
それでは、実際にUIアクションを作成する。
今回はインシデントテーブル[incident]を継承したテーブルにUIアクションを作成する。また、「コメント」フィールドは事前に作成してある。
##仕様
- ボタンの表示条件は、ステータスが"処理中"の時。
- ボタン押下時にステータスを”処理中”から”解決済み”に遷移する。
- ステータスを遷移する前に”コメント”フィールドに記入があるか検証する。
- ”コメント”に記入がない場合、エラーメッセージを表示、ステータスの遷移は行わない。
##実装
スクリプト以外のUIアクションは以下の画像のように設定した。
”条件”フィールドには current.state==2
を記述している。
インシデントテーブルのステータス"処理中"の値は2であるため、現在のステータスが処理中のときという条件文になる。
スクリプトに関しては以下のように記述
// ----- クライアントサイド -----
//フィールドの入力をチェックします。"クリック時"フィールドはこの関数から実行される。
function checkField(){
//コメントフィールドの列名を格納
var fieldName = ['comment'];
//格納したフィールド文ループ
for(var i=0; i<fieldName.length; i++){
popMsg(fieldName[i]);
}
//UIアクションを呼び出して、クリック時の関数をスキップする。
gsftSubmit(null,g_form.getFormElement(),'change_state_resolved');
}
//エラーメッセージに関しての関数
function popMsg(field){
//説明フィールドに何も入力されていない場合
if(g_form.getValue(field)==''){
//既に何かしらのメッセージがある時のためにメッセージを非表示にする。
g_form.hideFieldMsg(field);
//コメントフィールドを必須にする。
g_form.setMandatory(field, true);
//メッセージを表示
g_form.showFieldMsg(field,'コメントに何か入力してください。','error');
return false;
}
}
//----- サーバサイド -----
//以下のif文でスクリプトがブラウザ内で実行されないかチェック。
//windowが"undefined"なら関数を実行。
if (typeof window == 'undefined')
serverStateToResolved();
function serverStateToResolved(){
//ステータスを解決済み[6]にする
current.state = 6;
//レコードの更新
current.update();
}
動作チェック
結論
UIアクションはクライアント、サーバサイドの処理を実行できるが、今回紹介したAPIを使用することにより、両サイドの処理が実行できるようになった。これにより、アクション実行前にフィールドの必須チェックを行うことができるため、UIアクションの処理の幅を増やすことができると思われる。
今回の記事がお役に立てば幸いである。
参考文献
- 【SNGURU】Client & Server Code in One UI Action
- 【stackoverflow】What's the purpose of if (typeof window !== 'undefined')