consentFlow フォームビルダー ライフサイクルイベント一覧

consentFlow フォームビルダーで利用可能なライフサイクルイベント一覧

logic のトリガーや form.on() で利用できるイベントの一覧です。
以下のイベント名は内部的に定義している特別なライフサイクルイベント

ここに挙げるイベントは、logic を設定したコンポーネント固有のものではなく、フォーム全体で共有されるイベントです。たとえば blur を購読したコンポーネントは、フォーム内のどの項目がフォーカスを失っても発火します。特定の項目に限定したい場合は、customAction 内で result[0](イベント引数)を見て絞り込みます(後述)。

イベント発火タイミング備考
initializedフォーム全体の初期化完了時(保存データの適用後、最初の change の直後に Form.io インスタンスごとに 1 回)内部的に保証する特別なライフサイクルイベント。customDefaultValue の評価後に発火するため、初期値を利用した処理に最適。
changeフィールドの値が変更された時consentFlow では change イベントを起点に serializeData() が実行され、申請フォームでは FormIOFieldJson、検索フォームでは SearchFieldJson に書き込まれる。どの項目の変更でも発火する。変更された項目は result[0].changed.component.key で判別できる。
blurフォーカスが外れた時入力完了後のバリデーションや補完処理に使用する。フォーム内の全項目で発火する。対象の項目は result[0](そのコンポーネントのインスタンス)。
focusフォーカスが当たった時関連フィールドの表示切り替えや入力補助の表示に活用できる。フォーム内の全項目で発火する。対象の項目は result[0](そのコンポーネントのインスタンス)。
submitフォームの送信時form.submit() の完了後に非同期で発火するが、consentFlow はその前に XPages 側の送信を始めるため、通常は発火しない。保存前後の処理には使えない。
errorバリデーションエラー発生時consentFlow の保存・申請・承認ボタンは、先に checkValidity() で検証を止めて独自のエラー一覧を表示するため、このイベントは発火しない。入力エラーの検知には validate.custom を使う。
renderフォームの描画完了時DOM 操作が必要な処理に使用する。initialized より前に発火する(実測の順: render → change → initialized)。
prevPage / nextPageウィザード形式のページ遷移時Wizard 形式のフォーム専用。通常の検索フォームでは使用しない。

ビルダーでの設定方法

ロジック → トリガーの「タイプ」で「イベント名」を選ぶと、イベント名の自由入力欄が表示されます(候補リストはありません)。ここに上記のイベント名を小文字のまま入力します。大文字と小文字は区別され、Initialized では発火しません。JSON では "trigger": { "type": "event", "event": "blur" } となります。

initialized イベントについて

initialized は内部的に定義している特別なライフサイクルイベントです。コンポーネントごとの初期化ではなく、フォーム全体の初期化が完了したときに発火します。 任意の文字列(カスタムイベント)とは異なり、開発者が form.emit() で手動発火しなくても フォームが必ず発火を保証します。 customDefaultValue の評価が完了した後に発火するため、初期値を前提とした処理を安全に記述できます。

logic JSON の例

{
  "name": "onInitialized",
  "trigger": {
    "type": "event",
    "event": "initialized"
  },
  "actions": [
    {
      "name": "doSomething",
      "type": "customAction",
      "customAction": "/* data には初期値が既にセット済み */"
    }
  ]
}

consentFlow での注意点

「文書を開いたとき 1 回だけ」実行したい処理は、initialized ではなく、予約キー scriptBlock のコンポーネントに cfAPI.form.onOpen(function (ctx) { ... }) を書く方法を推奨します。部分更新による再発火の抑止や、保存データの適用後に実行するタイミングを consentFlow 側が保証します。詳しくは「WEB フォームを開いたときに「1回だけ」処理を実行する」を参照してください。

consentFlowではAjax処理(XPagesの部分更新)発生すると WEBフォームが再描画され、initialized が再発火します。 ボタンクリックなど一度だけ実行したい処理には window._formioInitialized フラグなどによるガードが必須です。

if (!window._formioInitialized) {
  window._formioInitialized = true;

  // SearchFieldJson に初期データを書き込む
  var hidden = document.querySelector('input[id$="SearchFieldJson"]');
  if (hidden) {
    hidden.value = JSON.stringify(data); // data は customAction コンテキスト変数
  }

  // 300ms 後に検索ボタンをクリック
  setTimeout(function() {
    var btn = document.querySelector('button[id$="buttonWebFormSearch"]');
    if (btn) btn.click();
  }, 300);
}

customAction で使えるコンテキスト変数

logic の customAction 内で自動的に利用可能な変数の一覧です。

変数内容
dataフォーム全体の現在のデータオブジェクト。初期値・入力値ともに含む。form.submission.data と異なり、customAction コンテキストでは常に安全に参照できる。
instanceロジックが定義されているコンポーネントのインスタンス。instance.getValue() / instance.setValue() で操作可能。
formフォームのインスタンス。form.getComponent('key') で他コンポーネントを取得できる。form.submission は初期化タイミングによって未定義になる場合があるため注意。
component対象コンポーネントの JSON 定義オブジェクト(スキーマ)。
rowDataGrid や EditGrid 内のコンポーネントの場合、現在の行データ。通常の検索フォームでは使用しない。
resultイベント引数の配列。result[0] が第 1 引数。blur / focus では対象コンポーネントのインスタンス(result[0] === instance で「自分の項目だけ」に絞れる)、change では { data, changed: { component, instance, value, flags } }、error ではエラー配列、initialized では undefined。

注意事項

  • logic は textfield や hidden などの入力系コンポーネントに設定する。HTML要素 / コンテンツ コンポーネントには設定しない。 これらのコンポーネントはイベント名を翻訳辞書に通してから購読するため、日本語環境では error が「処理前に以下のエラーを修正してください。」、submit が「フォームの送信」というイベント名に置き換わり、永久に発火しません(blur / change / focus / render / initialized は辞書に無いため動作します)。
  • change を購読した customAction で value を書き換えない。 評価後の value は自コンポーネントの値として setValue されるため、change → 再発火の無限ループになります。表示用途は DOM への直接書き込みにするか、blur など change 以外のイベントで、別項目に instance.root.getComponent('キー').setValue(...) します。
  • initialized に「1 回だけ」の処理を書かない。 部分更新のたびに新しい Form.io インスタンスが作られ、再発火します。前述の cfAPI.form.onOpen を使います。

カスタムイベントの手動発火

form.emit() を使うと任意のイベントを手動発火できます。コンポーネント間を直接参照せずに連携させたい場合に有効です。

// 発火側
form.emit('myCustomEvent');

受け取り側は別コンポーネントの logic に以下のように定義します。

{
  "trigger": {
    "type": "event",
    "event": "myCustomEvent"
  }
}

実装例は、デモ環境の「キッチンシンク」フォームの「ロジック・計算」タブにある「ライフサイクルイベント」パネルを参照してください。