1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【ServiceNow】色々な方法でフィールドヘルプを試してみた【Workspace】

1
Posted at

初めに

本来もっと考えないといけないことがあるのですが現実逃避的に色々な検証をしています。
今回はその1つとしてワークスペースのフォームフィールドでヘルプの出し方を調べてみたのでここにまとめます。

PDI環境

試したPDI環境はこんな感じです。
Version: Zurich
image.png

準備

いつものようにこれように適当にワークスペース用のアプリを作成します。
image.png

今回はTaskとかの継承もせずにテーブルを適当に作ります。
image.png

テーブルを作成したら適当にフィールドを作っておきます。

・TextField:String型
・ChoiceField:Choice型
・HtmlField:HTML
・DateField:Date
・DateTimeField:DateTime
・RefereceField:Reference(sys_user)
・List RefereceField:List/Reference(sys_user)

image.png

フォームは適当にフィールドを並べておきます。
image.png

確認用のワークスペースも作成します。
image.png

アノテーション

フォーム注釈(アノテーション)はCSAとかの勉強してるとヘルプとかフィールドの説明をしたい時、最もはじめに考えるべきコンポーネントと言われています。
個人的にはフィールドメッセージの方が短文だとフィールド下部に来てわかりやすいのですが、実装の簡単さでいうとこちらが勝つのかなという所です。

TextFieldのヘルプとして配置します。
image.png

フォームで見てみるとこんな感じです。
image.png

アノテーションのいいところはHTMLも効くところです。
例えば、下のようにrich textでHTMLコードを書くとHyperLinkでのヘルプが可能となります。

<p><a title="HyperLink" href="https://qiita.com/" target="_blank" rel="noopener">HyperLinkだお</a></p>

また、多言語対応も一応出来る?らしいので試してみます。
フォーム注釈に複数の言語をサポートする
ServiceNow 動的アノテーション – アノテーションでの JavaScript の使用

PDIに日本語を入れていなかったので英語だけですが、sys_ui_messageを追加します。
image.png

image.png

Annotation TypeをTextにして、gs.getMessageしてみます。
image.png

ワークスペースではコードがそのまま表示されてしまいます。
image.png

プラットフォームを見てみるとgs.getMessageが効いているように見えます。
現時点(2026年2月)ではワークスペースでアノテーションを利用して多言語対応が難しいのかもしれないです。
image.png

ツールチップ/ヘルプテキスト(help tips)

次にツールチップ/ヘルプテキストを試してみます。

対象フィールドを選択し、Advanced viewから関連リストのLabelsを更に選択します。
image.png

Text FieldのHintに適切な文字を入力します。
image.png

同じように他のフィールドにも適用します。
ワークスぺースで確認する前に個人設定からDisplay > Show help tips on formsを有効にしておきます。
これをしておかないとhintは出ません。

image.png

hintを登録したフィールドラベルの隣にアイコンが出てきて、クリックする事でhintを表示する事が出来ます。
image.png

このヒントは言語ラベル毎に設定する事で簡単に多言語対応が出来そうですが、スクリプトやHTMLについて確認する限りでは使用できないみたいです。
また、上述の通り、個人設定を有効化しておかないと表示されないのでユーザーに必ず見てほしいヘルプについては別の方法を選択した方がいいかもしれません。

フィールドメッセージ

次にフィールドメッセージを試してみます。
OnLoadのClientScriptを作成して、各フィールドにメッセージを出します。

スクリプトはこんな感じです。

function getMessageWrap(messageKey) {
	var ret = getMessage(messageKey);
	console.log(ret);
	if(ret === messageKey) 
		ret = getMessage(messageKey);

	console.log(ret);
	return ret;
}

function onLoad() {
   //Type appropriate comment here, and begin script below
   g_form.showFieldMsg("textfield", "フィールドメッセージだお");
   g_form.showFieldMsg("choicefield", "チョイスです", false);
   g_form.showFieldMsg("htmlfield", "htmlfieldメッセージだお");
   g_form.showFieldMsg("datefield", "datefield");
   g_form.showFieldMsg("datetilefield", "datetilefieldだお");
   g_form.showFieldMsg("referencefield",  getMessageWrap("HelpText"));
   g_form.showFieldMsg("listreferencefield", "<p>AAAA</p>");
}

getMessageWrapを作っているのはたまにgetMessageがkeyを稀にですがそのまま返すことがあるからです。その対策にgetMessage関数の戻り値とkeyが一致していたら再度呼び出すようにしています。
クライアントスクリプト関数 getMessage() が、Service Portal およびワークスペースで予期される翻訳済みテキストを返さない

全部infoにしていますが見た目はこんな感じです。
image.png
残念ながらHTMLは使えないようです。多言語対応はgetMessageでやりやすいですが、ハイパーリンクなどの埋め込みは難しいみたいです。また、2026/2/3時点のZurichではワークスペースでフィールドメッセージを利用するとフィールドの値を変更してフォーカスを外すとフィールドメッセージが消えるバグが存在しています。。。

image.png
これに文字を入力してフォーカスを外すと下側のメッセージが消えます。

image.png

フィールドデコレーター(Client Script/Server Script)

コミュニティを見ているとワークスペースのTooltipやHintでよく候補としてあげられているフィールドデコレーター(FieldDecorator)を試してみます。

Studioからだとうまくいかないのでプラットフォームから作成します。
image.png

image.png

Field Decoratorを作成して、スクリプトはClient Scriptにしておきます。
image.png

上記を追加するとTextField内に指定したアイコンが追加されている事を確認できます。

image.png
※Tooltipを指定しているとホバーする事で表示できます。

image.png

Field Decoratorアイコンをクリックする事でメッセージが表示できます。
これの利点はHTMLを使えるところでしょうか。
Tooltipプロパティの多言語対応が難しそうですが、getMessageも使えるので多言語対応をしやすいですし、フィールドメッセージを表示する事も可能です。
ただし、フィールドデコレーターはかなり扱いやすいですがChoiceやHTMLフィールド等の一部のタイプでは利用出来ないので注意が必要です。

function onClick() {
    var link = '<a href="https://qiita.com/mototoke">Mypage</a>';
    var message = getMessage("HelpText") + ' ' + link + ' ';
    g_form.addInfoMessage(message);
}

image.png

Server Scriptでも良いですが、再描画が発生する関係からなのか分からないですが新規作成レコードだとエラーが発生します。

var link = '<a href="https://qiita.com/mototoke">Mypage</a>';
var message = gs.getMessage("HelpText") + ' ' + link + ' ';
gs.addInfoMessage(message);

image.png

Client Script、Server Script両方で読み取り専用にしてもクリックが可能のようです。
image.png

フィールドデコレーター + g_modal

正直、addInfoMessageくらいで十分だと思いますが、より丁寧にヘルプを出したり長文を出す必要があるのであればこういった事も可能です。

function onClick() {
	g_modal.alert(
		'これはヘルプテキストです.',
		"めちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章ですめちゃくちゃ長い文章です",
		() => {},
		{
			"buttonTitle": "読みました",
			"buttonType": "primary"
		}
	);
}

image.png

文章が長ければ自動的にスクロールもつけてくれるので便利ですね。

ハイパーリンクつけたい等あればボタンは二つ出てしまいますが、richTextを使うこともできます。

function onClick() {
	g_modal.richText(
		'これはヘルプテキストです.',
		`<p>TEST</p>
		<br />
		<p><a title="HyperLink" href="https://qiita.com/" target="_blank" rel="noopener">HyperLinkだお</a></p>
		`,
		() => {},
		{
			"cancelTitle": "閉じる",
			"confirmTitle": "読みました",
			"cancelType": "default ",
			"confirmType": "confirm"
		}
	);
}

image.png

フィールドデコレーター + UI Page

g_modalでも良いですが、見た目にこだわるならUI Pageを使うことも可能です。
今回はこだわらないですが簡単なUI Pageを作成して呼び出してみます。
簡単と言いつつjelly構文には慣れていないのでかなり時間がかかりました。(´・ω・`)悲しみ

  • 呼び出すUI Page
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
	<!-- message key を取得 -->
    <g:evaluate var="jvar_message_key"  expression="jelly.sysparm_message_key || RP.getWindowProperties().get('sysparm_message_key')" jelly="true"/>
	<!-- message を取得 -->
	<g:evaluate var="jvar_message" jelly="true">
		var key = jelly.sysparm_message_key;
        var message = gs.getMessage(key);
  		message = (message !== key) ? message : '';
		<!-- 最後に変数を評価する事でjvar_messageに代入される -->
		message;
    </g:evaluate>
    <div style="white-space:pre-line">
		<!-- message が存在する場合(jvar_messageが空じゃない) -->
        <j:if test="${!empty jvar_message}">
			<div style="white-space:pre-wrap;">
            	${jvar_message}
       		</div>
		</j:if>

		<!-- message が空の場合 -->
		<j:if test="${empty  jvar_message}">
			<div style="white-space:pre-wrap;">
            	メッセージが見つかりませんでした
       		</div>
		</j:if>
    </div>
</j:jelly>

image.png

本来はちゃんとロールつけるべきですが、PDI環境なのでadminで。
image.png

宣言アクションを以下のように修正します。

  • 呼び出し側
function onClick() {
	g_modal.showFrame({
		title: 'ヘルプなんですわ',
		url: '/x_1603370_helptest_Test Help UI Page.do?' + [
				'sysparm_message_key=' + "HelpText",
			].join('&'),
        height: '300px',
		width: '400px',
		hasLoadingMessage: true,
	});
}

PDIだからなのかわかりませんが、若干Loadingが長いですが、こんな感じで表示ができます。
image.png

フィールドデコレーター(UXF Client)

使った事がないので今回初めて触るのですが、
UXF Clientを利用しても同じような事が出来そうです。
今回やってみた感想として実装までの道のりがややこしく使いこなすには相当時間がかかりそうという印象です。
正直なところ、実際に触ってみてもリソース同士のつながりはまだ完全には理解できていません💦

最初に結論を書いておきます。

UXF Client(Declarative Action → UI Builder Modal)で
payload(title / message)を表示する場合、
payloadをModal コンポーネント内で直接参照は難しそう
※もしかしたらやり方があるのかもしれませんが私にはわかりませんでした💦
その為、今回は
event.payload → client state parameter に格納
state を Label / TextArea から参照
という構成でモーダル表示を実現しました

以下はその検証過程と実装例です。

最初に呼び出すモーダルをUIBuilderで作成します。
Recordの該当Viewを開きます。

ここでなぜかStudioのUIBuilderからもPlatformのUIBuilderからも対象のスコープが選べませんでした。
image.png

同様の問題になっている人が結構いるみたいです。
UI ビルダーでのスコープアクセス
UI ビルダーのスコープアクセス制限

仕方がないのでPluginsからinstall済みのUI BuilderをRepairしてみます。
image.png

image.png
一旦ここでインスタンスをRefreshしておきます。

上記の対応でスコープが選択できるようになりました\(^_^)/
image.png

本筋からそれましたが、ここでやりたかった事はmodal画面の作成です。
Content > ModalsのAdd newでCustomを選択します。
実際には用途に応じて使い分けが必要になると思います。
image.png

作成したModals > AlertをRenameしておきます。

  • Component label: Help TextModal
  • Component ID: help_text_label
    image.png

Modalの外観を作成します。
Header:Label Value
Body:TextArea
Footer:Button
をそれぞれ配置します。
image.png

ButtonのEventsにAdd handlerOpen or close modal dialogを設定しておきます。
image.png

image.png

次にBodyを選択してEventsにあるHandled eventsを作成します。
image.png

Event LabelはHelp Text Modal eventにして、Payload fieldsにtitlemessageをstringで追加しておきます。
image.png

イベントを作成したら上側のAdd event mappingから作成したHelp Text Modal eventを選択します。
image.png
image.png

その次にhandlerでOpen or close modal dialogを選択します。
image.png

対象は作成したHelp TextModalになります。
image.png

ひとまずUIBuilder側の準備がこれで完了です。

次にプラットフォームから新しいDeclative Actionを作成します。
image.png

Field deoratorを選びます。
image.png

Action Payload Definitionsの定義も必要なのでこの画面から新規作成します。
image.png

Payload部分は以下のように定義しておきます。
image.png

{
  "type": "MAP_CONTAINER",
  "container": {
    "title": {
      "type": "EVENT_PAYLOAD_BINDING",
      "binding": {
        "address": ["title"]
      }
    },
    "message": {
      "type": "EVENT_PAYLOAD_BINDING",
      "binding": {
        "address": ["message"]
      }
    }
  }
}

image.png

次にAction Assingmentの関連リストにあるAction Model Fieldsで新規作成します。
image.png

新規作成するのは以下の2つです。
image.png
image.png

あまりよくわかっていないですがNOW Developer 5.2曰く
この変数同士がつながるようです?
image.png

次に、Action Assignment のタブでUX Add-on Event Mappings を開きます。
image.png

設定はこんな感じです。
image.png

今一つ結びつきがわかっていないのですが、Action Payload Definitionで定義したPayloadをコピーしてUX Add-on Event MappingのTarget Payload Mappingにペーストしないといけないようです。
image.png

ここまで来たらワークスペースの画面にあるアイコンからモーダルが開くことを確認できました。(...長かった)
image.png

なぜかCloseも動いていないのでボタンを押したらモーダルが閉じるようにするのと
TitleとMessageを渡して表示が出来れば良さそうです。

閉じない原因はすぐにわかりました。
ボタンのイベントでOpen modal dialogにチェックを入れていたのでこれを外すだけで良かったです。
image.png

ただここからがどうやってUIBuilder側に値を渡せるのか、Modalのlabelとtextareaに変数を表示できるのか不明でした。
一旦、payloadの定義を書き換えて静的に渡すことが出来ているのか試すことにしました。
Action Payload DefinitionのPayloadとUX Add-on Event MappingのTarget Payload Mappingを下記のようにします。
image.png
image.png

UIBuilderを色々見てたらeventのpayloadにmessageとtitleがあるのを発見しました。
そこで実際に値が来ているのかconsoleに表示して確かめてみました。
image.png

コンソールログを見てみると確かに値はUIBuilder側に来ていそうです。
image.png

そうなるとeventが受け取っているpayloadをどうやって参照するかになってくるのですが、何となくModal Openのhandlerだけでは無理そうだと思いました。
その為、ここでeventのmappingを修正します。
元々、event mappingで定義していたOpen or close modal dialogを1度削除します。
image.png

次にClient stete parametersを定義します。
titleとmessageを定義して閉じます。
image.png

再度、Add event mappingをクリックし、Help Text Modal eventを選択します。
image.png

Continueしてtitleを指定します。
image.png

Bind DataにEvent payloadにあるtitleを指定します。
image.png

同じようにmessageもAdd event mappingでHelp Text Modal eventにつなげておきます。

ここで再度、Add event mappingでHelp Text Modal eventとOpen or close modal dialogを定義しなおします。
1度削除したのは何となくイベントの順番が作成した順番になるんじゃないかと思ったからです。
3つ定義出来たら以下のようになります。
image.png

Modalのlabelとtextareaはそれぞれのvalueにclient state parameterを参照するようにしておきます。
image.png
image.png

これでUIBuilderを保存して、ワークスペースでフィールドデコレーターをクリックすると
image.png
一応、Payloadで定義していたタイトルとメッセージを表示する事が出来ました。
もっとうまいことすれば動的に内容を変更して表示もできるのかもしれないですが、今の私のレベルでは難しいのとそろそろ力尽きてきたのでここらへんにしておきます。

おわりに

今回はワークスペースで色々なヘルプの出し方を調べてみました。
この記事の内容をChatgpt君がわかりやすくまとめてくれました。

方法 表示位置 HTML 多言語対応 ユーザー操作 Workspace向き 備考
フォーム注釈(アノテーション) フィールド周辺 / 上部 △(Workspaceでは制限あり) 常時表示 実装が最も簡単。Workspaceでは gs.getMessage() が効かないケースあり
ツールチップ / ヘルプテキスト(Hint) ラベル横アイコン クリック 個人設定「Show help tips」が必要
フィールドメッセージ フィールド下部 常時表示 Zurich時点で入力後に消える不具合あり
フィールドデコレーター(Client Script) フィールド横アイコン クリック 最も柔軟。Choice / HTML フィールドでは使用不可
フィールドデコレーター(Server Script) フィールド横アイコン クリック 新規レコード時にエラーが出ることあり
フィールドデコレーター + g_modal モーダル △(テキスト中心) クリック 長文・スクロール対応が楽
フィールドデコレーター + UI Page モーダル クリック 見た目自由度最大。実装コスト高
フィールドデコレーター(UXF Client) フィールド横アイコン クリック 情報が少ない。手順がかなり複雑。実装コスト高。

個人的な所感をまとめるとこんな感じでしょうか。

  • 個人的な所感(まとめ)

    • 短文・常時見せたい説明
      → フォーム注釈 / フィールドメッセージ
  • ユーザーが必要な時だけ確認するヘルプ

    • → フィールドデコレーター
  • 長文・HTML・リンク必須

    • → フィールドデコレーター + g_modal / UI Page
  • 将来性・Workspaceネイティブ重視

    • → UXF Client

「これが唯一の正解」という方法はなく、
「どれくらい見せたいか」 「どれくらい凝りたいか」 「ユーザーにとって必須 or 任意」等で使い分けるのが現実的だと感じました。

Servicenowで何かをやろうとするとやり方が色々あったり、プラットフォームとワークスペースで出来る事と出来ないことが違ったり、そもそもの情報が少なかったりと思っていたよりも時間がかかってしまいました。
ですが実際に触れる事で色々分かった事もあったので良かったと思います。
拙い記事ですがどなたかの参考になれば幸いです。

UXF Client周り誰かわかりやすい解説記事書いてくれないかなぁ

参考URL

以下のURLを参考にしました。有益なサイト達に感謝します。
ServiceNow 動的アノテーション – アノテーションでの JavaScript の使用
フォーム注釈に複数の言語をサポートする
Support field hints in Workspace
クライアントスクリプト関数 getMessage() が、Service Portal およびワークスペースで予期される翻訳済みテキストを返さない
情報メッセージにハイパーリンクを追加する方法
UXF Client Declarative Action Create | UI Builder Day 16
[E17] You & I Builder Live! Field Decorator Declarative Actions
UIB: UI Action to initiate Modal Dialog created in UI Builder
UI ビルダー でのモーダルの作成
コンポーネントへのモーダルの追加
Opening a modal from Configurable Workspaces (Next Experience / UI Builder / Declarative Actions)
Opening a modal from a record in Configurable Workspaces
ServiceNow の宣言型アクション:完全ガイド
Using event payloads in UI Builder
UI ビルダーのイベントペイロード

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?