はじめに:なぜ「動かない」は起きるのか
ServiceNowの学習で、わりと早い段階でぶつかるのが「クライアントスクリプトが動かない」問題です。書いたはずなのに反応がない。保存してもフォームが変わらない。onChangeが発火しない。焦りますよね。
ここで大事なのは、“コードの間違い”より前に、設定や適用範囲のズレが原因になりやすいということです。クライアントスクリプトは、サーバ側(Business Ruleなど)と違って、次の要素が噛み合って初めて動きます。
- どの画面(どのUI)で動かすのか
- どのテーブル/どのフィールド/どのビューが対象なのか
- どのタイミング(onLoad / onChange / onSubmit など)で動かすのか
- 競合する設定(UIポリシー、別のスクリプト、カタログ設定)がないか
この「ズレ」を体系的に潰せるようになると、試験対策としても実務としても強いです。暗記ではなく、“動く条件”を構造で理解できるからです。
この記事では、初学者がよく踏む典型パターンを、切り分け手順と具体例つきで整理します。
本番形式で慣れるのが合格への近道。UdemyのServiceNow模擬問題集を人気順で一覧比較できます👇
典型原因その1:種類・対象・条件のズレ
「動かない」とき、最初に見るべきはコードよりレコード設定です。クライアントスクリプトは“正しい場所に置かれていない”と、何も起きません。
テーブルが違う
Incidentで作ったつもりが、実は拡張テーブル側に置いていた、あるいは逆…というパターンがあります。
フォーム上で見ているレコードがどのテーブルかは、画面上の情報や辞書、URLなどでも確認できます。
- 今開いているフォームがどのテーブルかをまず確定
- 継承(extends)がある場合、どの階層に置くべきかを考える
- 親(例:task)に置けば広く効く
- 子(例:incident)に置けば限定して効く
「どこに置くと、どこまで影響するか」はCSA学習でも混乱しやすいポイントです。
クライアントスクリプトの種類が違う
同じ“クライアントスクリプト”でも、レコードフォーム用とサービスカタログ用は別物です。
- Record Client Script:通常のテーブルフォーム(incidentなど)
- Catalog Client Script:カタログアイテム、レコードプロデューサ、変数(Variables)周り
カタログ変数で動かしたいのに、レコード側に書いても当然動きません。逆も同様です。
「今触っているのはフォームなのか、カタログなのか」を最初に言語化すると迷子になりにくいです。
UI Type / View / Applies to のズレ
環境によって表示するビューが違うと、スクリプトの適用ビューが合わず動かないことがあります。
また、特定UIだけ対象にしている設定(UI Typeなど)も見落としがちです。
チェック観点の例:
- Applies to(対象):All / Desktop / Mobile などの指定が意図通りか
- View:スクリプトが特定ビューに限定されていないか(または逆に限定したいのにAllになっていないか)
- Active:基本ですが、地味にあります
条件(Condition)が常に false
「条件付きで動かす」つもりが、条件が厳しすぎて一度もtrueになっていないケースです。
慣れないうちは、まず条件を外して動作確認→条件を戻す、が安全です。
コツ:動作確認用に一時的なメッセージを出す
g_form.addInfoMessage('Client Script fired');
これだけでも「発火してる/してない」が一瞬で分かります。
典型原因その2:実行タイミングとイベントの誤解
クライアントスクリプトは「いつ動くか」を間違えると、書いていても無音になります。
onChangeが発火しない代表例:「ロード中」と「同じ値」
onChangeは基本的にユーザー操作で値が変わったときに発火します。よくある勘違いは次の2つです。
- フォーム表示直後に動くと思っていた(→それはonLoad寄り)
- 同じ値を再セットしている(値が変わっていないので発火しない)
さらに、onChangeには多くの場合 isLoading が渡されます。フォームロード中に余計な処理をしないよう、よく次のように書きます。
- ロード中はreturnする
- 空値ならreturnする
これ自体は良いのですが、return条件が強すぎて、実質いつもreturnになっていることがあります。
例:空値チェックが厳しく、ユーザーが選ぶ前に抜ける
例:ロード判定の扱いが雑で、ユーザー操作でも抜ける
まずはチェックを最小限にして、発火を確認してから守りを固めるのが近道です。
onLoadに書いたのに期待通りにならない:「値がまだない」
onLoadはフォームが読み込まれたタイミングですが、関連データや参照情報が完全に揃う前のこともあります。
参照先から値を取る、グライドAJAXで何か引く、といった処理は、順番の影響を受けやすいです。
この場合は、
- そもそもonLoadでやる必要があるか
- UIポリシーやデフォルト値設定で代替できないか
- 非同期処理(コールバック)の書き方が正しいか
を考えます。
onSubmitが「保存時」だと思っていた
onSubmitは保存ボタン等で送信される直前に動きますが、UIの動きや必須チェック、別の仕組みとの組み合わせで「思ったタイミングと違う」ことが起こります。
例えば、onSubmitで値をセットしても、別のバリデーションで止まる、別スクリプトで上書きされる、などです。
「保存前に必須チェックしたい」のか「保存直前に値を整形したい」のか、目的を分けると設計しやすいです。
典型原因その3:UI体験の違いと競合
「単体では正しいのに効かない」ときは、競合を疑います。
UIポリシーが上書きしている
初心者が混乱しやすいのがこれです。たとえば、
- クライアントスクリプトで
g_form.setReadOnly(false)にした - でもUIポリシーが同じフィールドをRead-onlyにしている
- 結果:見た目は変わらない(または一瞬変わって戻る)
UIポリシーはノーコードで強力ですが、同じフィールドに対して複数の制御があると、最終的にどれが勝っているかを追いづらくなります。
まずは、対象フィールドに関係するUIポリシーを洗い出して、当たりを付けましょう。
同じイベントに複数スクリプトがいる
onChangeが複数ある、UI ScriptやUI Actionが絡む、クライアント側ライブラリが入っている、など。
このとき起きるのが「後から動いた処理が上書きする」問題です。
対策としては、
- 一時的に対象スクリプト以外を無効化して比較する
- 何が最後に値を変えたかをログで追う(console.logなど)
- 役割を分ける(値セット担当と表示制御担当を混ぜない)
Workspace / UIの違いで動作が変わる
環境によっては、同じフォームでも体験が異なります。いわゆる“どのUIで開いているか”です。
この話は深掘りすると長いですが、初学者の段階ではまず、
- 自分が今見ている画面は、想定していたUIと同じか
- 「そのUIで」クライアントスクリプトが想定通り発火する設定になっているか
を確認するだけでも、ハマりが減ります。
典型原因その4:デバッグ手順と“再現できない”問題の潰し方
「動かない」を短時間で切り分けるには、順番が大事です。おすすめの流れはこれです。
まず発火確認:最小の目印を入れる
最初にやるのは、コードの正しさ以前に「発火しているか」を確定することです。
g_form.addInfoMessage('fired');- 可能なら
console.log('fired');(ブラウザ開発者ツール)
これで、発火していない=設定/対象/条件/UIの問題
発火している=コードの中身/競合/タイミングの問題
と切り分けができます。
変数・フィールド名の勘違いを疑う
g_form系で多いのが「表示名」と「内部名」の取り違えです。
- 画面のラベル:例「Caller」
- 内部名:例
caller_id
g_form.getValue('Caller') のようにラベルを入れてしまうと動きません。
辞書(Dictionary)で内部名を確認する癖をつけると、ここは安定します。
キャッシュ・反映遅延を疑う
変更したのに古い動作が残るときは、ブラウザキャッシュや反映のタイムラグもありえます。
ただ、むやみに疑うと時間が溶けるので、まずは発火確認→設定確認→競合確認の後で「最後の手段」くらいの位置づけが良いです。
権限・ACLの影響で“見えてない/編集できない”ケース
「スクリプトは動いているのに値が入らない」場合、ユーザー権限側の制約が絡むことがあります。
たとえば、ユーザーが編集できないフィールドに setValue しようとしても、結果が見た目に反映されない(または保存されない)ことがあります。
ここは“クライアントスクリプトが悪い”と決めつけず、フィールドがそもそも編集可能かを確認すると早いです。
典型原因その5:現場で効くパターン別処方箋
ここからは、よくある症状→原因→対処をセットで整理します。初学者が「次に何を見ればいいか」が分かる形にしています。
ケース:onChangeがまったく動かない
ありがちな原因
- 対象フィールドが違う(内部名ミス、別フィールドを見ている)
- 条件がfalse(Condition、Applies to、View)
- CatalogとRecordを取り違えている
対処
- 対象フィールドの内部名を辞書で確認
- 条件を一旦外し、
addInfoMessageで発火確認 - カタログならCatalog Client Script/変数イベント側に置き直す
ケース:一瞬だけ動いて元に戻る
ありがちな原因
- UIポリシーや別スクリプトが上書き
- 2つ以上のonChangeが同じフィールドを触っている
対処
- 対象フィールドに関わるUIポリシーを洗い出す
- いったん片方を無効化して挙動比較
- “表示制御”と“値セット”の役割を分けて整理する
ケース:g_form.setValueしたのに値が変わらない
ありがちな原因
- 指定したフィールド名が間違い
- フィールドが読み取り専用(UIポリシー含む)
- 参照フィールドで、入れる値の形式を誤解している(sys_idが必要など)
対処
- 内部名の再確認
- 読み取り専用の原因を(UIポリシー/権限/フォーム設定)で切り分け
- 参照フィールドは「表示値」と「実体(sys_id)」の違いを意識して設計する
ケース:特定ユーザーだけ動かない/環境で再現しない
ありがちな原因
- ロールやACLで編集可否が違う
- ビューやフォームレイアウトが違う(見ている画面が別)
- UI体験が違う(開き方が違う)
対処
- そのユーザーで「どのビュー」「どのUI」で開いているかを合わせる
- フィールド権限(編集可否)を確認する
- “同じ条件で再現する”を最優先にして、再現できてから原因を掘る
まとめ:原因は「ズレ」「順番」「競合」。体系で覚えると強い
クライアントスクリプトが動かないとき、原因は大きくこの3つに収束します。
- ズレ:テーブル、種類(カタログ/レコード)、対象フィールド、ビュー、条件
- 順番:onLoad/onChange/onSubmitのタイミング、ロード中、非同期の扱い
- 競合:UIポリシー、他スクリプト、別UIでの挙動差
この3分類で考えるだけで、「何を調べるべきか」が整理され、闇雲に試行錯誤する時間が減ります。CSA学習としても、単なる暗記より“仕組みの前提”が積み上がるので、他の領域(UIポリシー、ACL、フォーム設計)にも理解が波及します。
もし「原因の切り分けは分かったけど、そもそもクライアント側の基本(g_form、イベント、カタログとの違い)を一気に整理したい」と感じたら、体系的にまとまった教材を1つだけ軸にするのも手です。Udemyには、フォーム制御やクライアント側の基礎を章立てで学べる講座もあるので、「自分の理解が抜けやすい部分を埋める」目的で使うと相性が良いと思います。
本番形式で慣れるのが合格への近道。UdemyのServiceNow模擬問題集を人気順で一覧比較できます👇

