widget-coherence について
ServiceNow Service Portal のウィジェット開発向けスキルで、サーバースクリプト、クライアントコントローラー、HTML テンプレートの整合性を扱います。データやアクションの流れを確認し、デプロイ前に不一致を見つけるための指針を提供します。
主な機能
- 01ウィジェット三者間の契約確認
- 02サーバーとクライアントのアクション照合
- 03データプロパティ初期化の指針
- 04Angular ディレクティブの一覧
- 05デプロイ前の検証チェックリスト
活用シーン
- 01ウィジェットのデータバインディング確認
- 02クライアントとサーバーのアクション不一致の発見
- 03クリックハンドラーとコントローラーメソッドの照合
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ serac-labs/ serac --skill widget-coherenceインストール後、Claude Code で/widget-coherenceを入力して読み込まれたか確認します。
詳細
ServiceNow Service Portal のウィジェットの整合性
Service Portal のウィジェットでは、サーバースクリプト、クライアントコントローラー、HTML テンプレート間で完全に通信できる必要があります。これは必須です。これらのコンポーネントが正しく連携しないと、ウィジェットは動作しません。
3 者間の契約
すべてのウィジェットで、同期された通信が必要です。
1. サーバースクリプトの要件:
- HTML が参照するすべての
data.*プロパティを初期化する - クライアントが
c.server.get()経由で送信するすべてのinput.actionを処理する - クライアントが期待する形式でデータを返す
2. クライアントコントローラーの要件:
- HTML の
ng-clickから呼び出されるすべてのメソッドを実装する - サーバーとの通信には
c.server.get({action: 'name'})を使用する - サーバーから応答があったら
c.dataを更新する
3. HTML テンプレートの要件:
- サーバーが提供する
data.*プロパティのみを参照する - クライアントコントローラーで定義されているメソッドのみを呼び出す
- 正しい Angular ディレクティブとバインディングを使用する
データフローのパターン
サーバー → クライアント → HTML
// SERVER SCRIPT
;(function () {
data.incidents = []
data.loading = true
var gr = new GlideRecord("incident")
gr.addQuery("active", true)
gr.setLimit(10)
gr.query()
while (gr.next()) {
data.incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
})
}
data.loading = false
})()
// CLIENT CONTROLLER
api.controller = function ($scope) {
var c = this
c.selectIncident = function (incident) {
c.selectedIncident = incident
}
}
<div ng-if="data.loading">Loading...</div>
<div ng-if="!data.loading">
<div ng-repeat="incident in data.incidents" ng-click="c.selectIncident(incident)">
{{incident.number}}: {{incident.short_description}}
</div>
</div>
クライアント → サーバー(アクション)
// CLIENT CONTROLLER
c.saveIncident = function () {
c.server
.get({
action: "save_incident",
incident_data: c.formData,
})
.then(function (response) {
if (response.data.success) {
c.data.message = "Saved successfully"
}
})
}
// SERVER SCRIPT
if (input && input.action === "save_incident") {
var gr = new GlideRecord("incident")
gr.initialize()
gr.setValue("short_description", input.incident_data.short_description)
data.new_sys_id = gr.insert()
data.success = !!data.new_sys_id
}
検証チェックリスト
ウィジェットをデプロイする前に、次の点を確認してください。
- サーバーのすべての
data.propertyが HTML またはクライアントで使用されている - すべての
ng-click="c.method()"に、クライアント側の対応するc.methodがある - すべての
c.server.get({action: 'x'})に、サーバー側の対応するif(input.action === 'x')がある - 対応する呼び出しがないメソッドや未使用のデータプロパティがない
- すべての
data.*プロパティがサーバーで初期化されている(空の場合も含む)
よくある失敗
アクション名の不一致
// CLIENT - sends 'saveIncident'
c.server.get({ action: "saveIncident" })
// SERVER - expects 'save_incident' (MISMATCH!)
if (input.action === "save_incident") {
}
メソッド名の不一致
<button ng-click="c.saveData()">Save</button>
// CLIENT - defines save() (MISMATCH!)
c.save = function () {}
未定義のデータプロパティ
<span>{{data.user.email}}</span>
// SERVER - only sets user.name (user.email is undefined!)
data.user = { name: userName }
Angular ディレクティブのリファレンス
| ディレクティブ | 目的 |
|---|---|
ng-if | 条件に応じて要素をレンダリングする |
ng-show/ng-hide | 表示を切り替える(要素は DOM に残ります) |
ng-repeat | 配列を反復処理する |
ng-click | クリックイベントを処理する |
ng-model | 双方向のデータバインディング |
ng-class | CSS クラスを動的に設定する |
ng-disabled | フォーム要素を無効にする |
コメント
Markdown 対応