Notes のフォームイベントは WEB フォームのどこに書くか(PostOpen / QueryModeChange / QuerySave / Click の対応表。4.4.0 のフォームスクリプト対応)

この記事で分かること

この記事は、Notes/Domino のアプリを使っている方全般に向けた記事です。 Notes のフォームを WEB フォームに作り直すときに、これまでの書き方をどこへ移せばよいかが分かります。

Notes のフォームは、QueryOpen → PostOpen → (入力)→ QuerySave → PostSave → QueryClose と、イベントが順に起きる前提で作られています。
consentFlow の WEB フォームは、一見、これらにそのまま当たるイベントがありません。
ただし、同じ目的を果たす書き場所は用意されています。
この記事では、Notes のフォームイベントやフィールド式を WEB フォームの「どこに書くか」を対応表にまとめ、画面側(フォームビルダー)で済ませるものと、サーバー側(プロコードのフック)に置くものの分け方を説明します。

対象: Notes/Domino のユーザー全般。
Notes のフォームを WEB フォームに作り直す方、プロコード開発を担当する方。
consentFlow 4.4.0 以降(4.4.0 より前の環境での PostOpen の置き換えは、関連記事「1回だけ処理を実行する」の末尾を参照)。

前提: 考え方の違い

Notes のフォームconsentFlow の WEB フォーム
動く仕組みイベント(QueryOpen、PostOpen、Exiting、QuerySave…)が決まった順に起きる各フィールドに付けた式(計算値・条件表示・検証)が、開いたときと値が変わるたびに評価される
書き方の中心「いつ」動くかをイベントごとに書く「どんな条件のとき」どうなるかをフィールドごとに書く
再計算F9 や保存のときに式を再計算する値が変わると、それに依存する式が自動で再評価される
確定処理(採番、履歴、連携)QuerySave / PostSave に書く画面側ではなく、サーバー側のプロコードのフックか、Notes エージェントの呼び出し設定に置く

つまり、「PostOpen に書いていた処理」をそのまま 1 か所に移す場所はなく、目的ごとに置き場所を選びます。

対応表: Notes のイベント → WEB フォームの書き場所

Notes のフォームイベントと、WEB フォームでの書き場所の対応図

フォームを開くとき

Notes目的WEB フォームでの書き場所補足
QueryOpen開く前の判定、表示の準備サーバー側: customFormBeforePageLoad()(表示前)/ customFormAfterPageLoad()(表示後)画面側で「開かせない」制御はしません。見せる・見せないは条件表示で
PostOpen開いた直後に初期値を入れる、マスタを 1 回読むフォームスクリプト(予約キー scriptBlock)に cfAPI.form.onOpen(fn) を登録ページ表示ごとに 1 回だけ呼ばれ、部分更新で再実行されません。コールバックの中で ctx.set('キー', 値) で項目に書きます(関連記事「1回だけ処理を実行する」)
PostOpen(新規作成時だけ)作成時刻・作成者・作成時点の所属を記録フォームスクリプトの cfAPI.form.onNew(fn)新規作成のときだけ 1 回。保存する非表示フィールドに書きます
(既存文書のデータ移行)古い文書を開いたときに値を直すフォームスクリプトの cfAPI.form.migrate(番号, fn)未実施の文書を編集モードで開いたとき、番号の昇順に 1 回ずつ
QueryModeChange / @IsDocBeingEdited編集モードか参照モードかで分けるcfGlobal.editable を条件表示・計算値の条件に使うWEB フォームにモードの切り替えはありません。参照モードでは入力欄そのものが編集できない状態で表示されます
@IsNewDoc新規作成かどうかcfGlobal.isNewNote「新規作成時に1回だけ」のガードに使います

入力中(フィールドの式・イベント)

NotesWEB フォームでの書き場所補足
Default value(固定の初期値)初期値(defaultValue)固定値はこれで十分
Default value(式)/ Computed when composed項目 1 つなら計算値 + cfGlobal.isNewNote かつ「値が空のとき」のガード。複数項目や副作用を伴うならフォームスクリプトの cfAPI.form.onNew(fn)初期値に式を書いても、公開した時点の値がフォーム定義に焼き込まれるため、開くたびには評価されません
Computed / Computed for display計算値(calculateValue)表示だけの値は「保存しない(persistent: false)」に
Hide-when 式条件表示(簡易な条件、または customConditional)ロール(cfGlobal)、編集可否、他の項目の値で出し分けられます
Input Validation検証(validate.custom。valid = true か、エラーメッセージの文字列)保存・申請の前に止まります。下書きの間だけ緩くする、といった条件も書けます
Input Translation(入力値の整形)logic(イベント blur または change)の customAction で値を書き換える。既存文書の一括正規化はフォームスクリプトの migrate全角→半角、前後の空白の除去など
Entering / Exitinglogic(イベント focus / blur)入力補助の表示、入力後の補完に
OnChange他の項目の計算値(自動で再評価される)、または logic(イベント change)「A が変わったら B を計算」は、B の計算値に書くだけで足ります
キーワード式(@DbColumn / @DbLookup)選択コンポーネントのデータソース URL(ビュー参照)関連記事「選択肢を他の DB・ビューから取り込む」
PostRecalc / F9(不要)値が変わると依存する式が自動で再評価されます

ボタンを押したとき

NotesWEB フォームでの書き場所補足
アクション/ホットスポットの Clickボタンコンポーネントの action: custom(JavaScript を書く)data(フォームの値)、form.getComponent('キー')、cfGlobal が使えます
他の処理に「合図」を送るボタンの action: event(イベント名を付ける)→ 受け取る側のコンポーネントの logic(trigger: event)コンポーネント同士を直接参照せずに連携できます
申請・承認ボタンに独自のチェックを挟むサーバー側: customExtApplyOnClick()/customExtApplyOnClickAfter() ほか(下記)false を返すと処理を中止できます

保存・申請・承認のとき

Notes目的WEB フォームでの書き場所補足
QuerySave(入力チェック)不備があれば保存させない画面側: 必須と検証(validate)画面側だけで止まります
QuerySave(確定処理の前のチェック)条件を満たさなければ申請・承認を止めるサーバー側: customExtApplyOnClick() / customExtApproveOnClick() / customExtSendbackOnClick() / customExtDenyOnClick() / customExtPullbackOnClick()戻り値 true で続行、false で中止
QuerySave / PostSave(履歴の記録、項目の書き込み)承認者の情報や日時を項目に残すサーバー側: 保存直前に呼ばれる customExtApplyOnClickAfter() / customExtApproveOnClickAfter() / customExtSendbackOnClickAfter() / customExtDenyOnClickAfter() / customExtPullbackOnClickAfter()(承認・差し戻しなどの全アクションにあります)の中で項目に書く例は既存 TIPS「申請部門の最終承認者の ID・漢字名・役職をフィールド保存したい」
PostSave / WebQuerySave(連携、後処理)保存後に他システムへ連携、Notes のエージェントを動かす外部システム連携(AGENT)の「保存」「下書き保存」トリガ既存の LotusScript / Java エージェントを、保存の後に設定だけで呼べます
QueryClose閉じるときの後始末(不要)ブラウザのタブを閉じるだけです

典型例 3 つ

以下は考え方を示す例です。コード中のキー名(createdSection など)は例なので、自分のフォームの項目名に置き換えてください。

1. 開いたときにログインユーザーの所属を入れる(PostOpen の置き換え)

フォームスクリプト(キー scriptBlock の非表示 HTML 要素)の本文に、新規作成時のコールバックを登録します。
以下のコードは書き方を示す例です。
createdSection と createdBy は例として付けた項目名で、製品が決めた名前ではありません。
自分のフォームに、保存する非表示フィールドとして好きな名前で置いてください。

cfAPI.form.onNew(function (ctx) {
  ctx.set('createdSection', cfGlobal.sectionName || '');
  ctx.set('createdBy', cfGlobal.currentUserName || '');
});

承認者が開いても値は変わらず、保存して開き直しても作成時の所属が残ります。
項目が 1 つだけなら、その項目の計算値に if (typeof cfGlobal !== 'undefined' && cfGlobal.isNewNote && !value) { value = cfGlobal.sectionName || ''; } と書く従来の方法でもかまいません。
詳しくは関連記事「1回だけ処理を実行する」と「ログインユーザーの氏名・所属・ロールを使う」を参照してください。

2. 条件で編集を抑止する(Hide-when / QueryModeChange の置き換え)

「申請後は金額欄を見せない」「管理者ロール以外には備考欄を出さない」は、対象のコンポーネントの条件表示(customConditional)に書きます。

// 下書きの間(未採番)か、編集できる状態のときだけ表示する
show = (typeof cfGlobal === 'undefined')
  || (cfGlobal.applicationNo === '' && cfGlobal.editable === true);

参照モードでは、もともと入力欄は編集できません。「見せるが触らせない」は条件表示ではなく、参照モードに任せるのが簡単です。

3. 承認時に承認者の情報を項目に書く(QuerySave / PostSave の置き換え)

画面側のロジックは、承認者が参照モードで開くだけでも動きますし、ブラウザで止めることもできます。
「承認のときに必ず 1 回」行う処理は、サーバー側の customExtApproveOnClick() に書きます。
処理の後に return true; で承認を続行し、条件を満たさないときは利用者に知らせて return false; で中止します。
実装例は既存 TIPS「申請部門の最終承認者の ID・漢字名・役職をフィールド保存したい」にあります。

「保存時に 1 回だけ、確実に」はプロコード側で

サーバー側のフックは、プロコード領域の SSJS ライブラリ customLib_SSJS.jss に、決まった名前の関数として書きます。製品本体のコードとは分かれているため、製品を更新しても上書きされません。

分類関数名呼ばれるとき
初期化customInitApp()アプリの読み込み時に 1 回
フォームの表示customFormBeforePageLoad() / customFormAfterPageLoad()フォームの表示前/表示後
customFormAfterRestoreView() / customFormBeforeRenderResponse() / customFormAfterRenderResponse()画面の復元・描画の前後(部分更新のたびに呼ばれる点に注意)
アクションボタンcustomExtApplyOnClick()(申請)/ customExtApproveOnClick()(承認)/ customExtSendbackOnClick()(差し戻し)/ customExtDenyOnClick()(否認)/ customExtPullbackOnClick()(引き戻し)各ボタンを押したとき、承認コメントのダイアログが表示される前。true で続行、false で中止
customExtApplyOnClickAfter() / customExtApproveOnClickAfter() / customExtSendbackOnClickAfter() / customExtDenyOnClickAfter() / customExtPullbackOnClickAfter()各ボタンの処理で、保存の直前

どのアクションにも、末尾に After が付かないフック(OnClick)と付くフック(OnClickAfter)の 2 つがあります。使い分けは次のとおりです。

  • OnClick(customExtApplyOnClick() など): 承認コメントのダイアログが表示される前に呼ばれます。入力チェックなど、条件を満たさないときに処理を止める用途に使います
  • OnClickAfter(customExtApplyOnClickAfter()、customExtApproveOnClickAfter()、customExtSendbackOnClickAfter()、customExtDenyOnClickAfter()、customExtPullbackOnClickAfter()): 保存の直前に呼ばれます。項目への書き込みなど、保存直前の処理に使います

「保存」「下書き保存」の直後に動かしたい処理が Notes のエージェントとして既にあるなら、プロコードを書かずに、外部システム連携(AGENT)の「保存」「下書き保存」トリガで呼び出せます。

結果の確認

  • 開いたときの処理: フォームを開き直しても、入力欄に何か打っても、値が意図したタイミングでしか変わらないこと
  • 条件表示: 下書き・申請後・承認者の参照モードの 3 つの状態で開き、見え方が意図どおりであること
  • サーバー側のフック: 条件を満たさない文書で申請・承認を行い、中止のメッセージが出て状態が進まないこと

補足・注意

  • フォームビルダーのプレビューでは cfGlobal が未定義です。式の先頭で typeof cfGlobal !== 'undefined' を確かめてください
  • 部分更新(Ajax)が起きると WEB フォームが再描画され、initialized などのイベントも再び起きます。「1 回だけ」にしたい処理は、フォームスクリプトの onOpen / onNew / migrate に書けば再実行されません(logic や計算値に書く場合はガードが必要です)
  • フォームビルダーのイベント名(initialized、change、blur、focus、render など)と、logic で使える変数は、既存記事「consentFlow フォームビルダー ライフサイクルイベント一覧」にまとまっています

関連記事