自作のボタンとダイアログを作る(ローコードでできる範囲と、プロコードの置き場所・共通関数)

この記事で分かること

フォームに自作のボタンを置き、「ボタンを押したらダイアログを出し、選んだ値を項目に反映する」処理を作りたい場面があります。consentFlow の WEB フォームでは、この多くをローコード(フォームビルダーのボタンコンポーネントと、ダイアログになるパネル)で作れます。この記事では、ローコードでできる範囲、ダイアログ(ピッカー)の作り方、複数のフォームで使う共通関数をどこに置くか(プロコード)、標準の申請・承認ボタンや画面の枠組みに手を入れるときの置き場所を説明します。

対象: フォームビルダーでフォームを作る方、プロコード開発を担当する方。consentFlow 4.x。

Notes/Domino から移行する方へ: Notes のフォームでは、アクションボタンと、LotusScript(Notes のスクリプト言語)のダイアログ命令 ws.DialogBox(別の画面を開いて値を選ばせる)・Inputbox(入力欄つきの小さな窓を出す)で、同じ処理を作っていました。この記事では、これらに当たる consentFlow の作り方を説明します。Notes/Domino を使ったことがない方は、この注釈は読み飛ばして構いません。

前提: どこまでがローコードで、どこからがプロコードか

やりたいこと ローコード(フォームビルダー) プロコード
フォーム内のボタン。押したら項目を計算・転記する、確認メッセージを出す ボタンコンポーネント(action: custom) 不要
ダイアログで選んで、親の項目に戻す(Notes の ws.DialogBox の置き換え) パネルの「モーダルで編集(modalEdit)」+ ボタン 不要
入力した語で他の DB を検索し、結果から選ぶ(Notes の Inputbox + 検索の置き換え) 同上。一時フィールドをビュー参照の選択コンポーネントにする 不要
複数のフォームで使う共通関数・定数 なし(ローコードに共通ライブラリの仕組みはありません) custom.js
標準の申請・承認ボタンに独自のチェックやメッセージを挟む 検証(validate)で止める SSJS フック customExtApplyOnClick() など
承認バーに独自ボタンを足す。左メニュー・ヘッダーに項目を足す なし 拡張スロット(ccCustomExtButtons、ccCustomLeftSidebar1 など)
既存の Notes エージェント(Notes に保存した自動処理のプログラム)をボタンで実行する(参照モード) 外部システム連携(AGENT)のアクションボタン(設定だけ。確認メッセージも設定できる) 不要
WEB ビューに独自のアクションボタンを置く なし(設定で出せるのは新規作成と CSV / Excel 出力) 必要

手順 1: フォーム内のボタン(押したら処理を実行する)

  1. フォームビルダーで ボタン コンポーネントを置き、Action を custom にします
  2. 「ボタンのカスタムロジック」に JavaScript を書きます。data(フォームの値)、form.getComponent('キー')、instance(このボタン)、cfGlobal(ログインユーザーや文書の状態)が使えます
  3. 処理の前に確認したいときは、ブラウザの confirm() で十分です
if (!confirm('更新日を今日の日付にします。よろしいですか?')) { return; }
form.getComponent('updatedAt').setValue(new Date().toLocaleDateString('ja-JP'));
  1. 「検証を表示(showValidations)」はオフにしておきます。オンのままだと、未入力の必須項目があるときにボタンの処理より先にエラー表示が出ます
  2. ボタンから他のコンポーネントの処理を呼びたいときは、Action を event にしてイベント名を付け、受け取る側のコンポーネントの logic に「trigger: event(同じ名前)」を書きます。コンポーネント同士を直接参照せずに連携できます

手順 2: ダイアログ(ピッカー)を作り、選んだ値を親に戻す

「担当者を選ぶダイアログを開き、選んだ人を『選択された担当者』に入れる」を例にします。

  1. 親のフォームに、結果を受ける項目を置きます(例: テキストフィールド pickedPerson。利用者が直接編集しないなら「無効(disabled)」に)
  2. パネル を置き(例: キー pickerPanel、タイトル「担当者を選択」)、パネルの設定で モーダルで編集(modalEdit) をオンにします。これだけで、フォーム上にはタイトルと「開く」ボタンだけが表示され、押すとパネルの中身がダイアログで開きます
  3. パネルの中に、一時フィールド(例: 選択コンポーネント pickerTmp。選択肢は固定の値でも、ビュー参照の URL でもかまいません)と、確定ボタン(pickerSet、Action: custom)を置きます
  4. 確定ボタンのカスタムロジックに次を書きます
var picked = data.pickerTmp || '';
if (!picked) { alert('担当者を選択してください'); return; }
form.getComponent('pickedPerson').setValue(picked);

// 一時フィールドの値はサーバーに送らない: 値を消してから閉じる
var tmp = form.getComponent('pickerTmp');
if (tmp) { try { tmp.setValue(null); } catch (e) {} }
try { delete data.pickerTmp; } catch (e) {}
try { if (root && root.data) { delete root.data.pickerTmp; } } catch (e) {}

// ダイアログを閉じる(「保存」を押したことにする。「閉じる」だと破棄の確認が出る)
var modalRoot = instance.element ? instance.element.closest('.formio-dialog-content') : null;
var saveBtn = modalRoot ? modalRoot.querySelector('[ref="modalSave"]') : null;
if (saveBtn) { saveBtn.click(); }

「開く」を押すと、パネルの中身(一時フィールドと確定ボタン)がダイアログで開く(デモ環境のキッチンシンクフォーム)

確定すると、選んだ値が親の「選択された担当者」に入り、ダイアログが閉じる(デモ環境のキッチンシンクフォーム)

他の DB を検索して選ぶ場合

Notes の Inputbox で語を入れて他 DB を検索していた処理は、一時フィールドをビュー参照の選択コンポーネント(データソース URL に restViewJson、検索フィールド keys)にすると、入力しながら候補が出る形で置き換えられます。候補を一覧(データグリッド)で見せて行の「選択」ボタンで親に戻す形も作れます。次の画面は、ダイアログの中で検索モードと検索語を指定してビューを検索し、結果の行の「選択」ボタンで文書を選ぶ例です。

ダイアログで他の DB のビューを検索し、結果の行の「選択」ボタンで文書を選ぶ例(デモ環境のキッチンシンクフォーム)

URL の組み立てと絞り込みは、関連記事「選択肢を他の DB・ビューから取り込む」を参照してください。

手順 3: 共通関数の置き場所(プロコード)

複数のフォームのボタンや計算値から同じ処理を呼びたいとき、ローコードには、Notes のスクリプトライブラリ(複数のフォームで共有する関数の置き場)に当たる仕組みがありません。プロコード領域のクライアント側 JavaScript custom.js に関数や定数を定義すると、どのフォームからでも呼べます。

  1. アプリケーションの Web 側のデータベース(データを保存する DB ではなく、画面を動かす DB)にある custom.js を開きます(プロコード領域。製品コードから分かれています)
  2. 関数名の衝突を避けるため、1 つのオブジェクトにまとめて定義することをお勧めします
// custom.js
window.myCo = window.myCo || {};
myCo.TAX_RATE = 0.1;
myCo.toHalfWidth = function (s) {
  return String(s || '').replace(/[A-Za-z0-9]/g, function (c) {
    return String.fromCharCode(c.charCodeAt(0) - 0xFEE0);
  });
};
  1. フォーム側(ボタンのカスタムロジック、計算値、logic の customAction)からは myCo.toHalfWidth(data.code) のように呼びます
  2. 見た目の共通化は custom.css に書きます。別のライブラリを読み込みたいときは、拡張スロット ccCustomResources に追加します

custom.js と custom.css はプロコード開発者のためのファイルで、製品コードはこれらに依存しません。ここに書いた処理でエラーが出ても製品の機能は止まらない設計で、製品を更新しても上書きされません。

手順 4: 標準のボタンや画面の枠組みに手を入れる(プロコード)

やりたいこと 置き場所 補足
申請・承認・差し戻し・否認・引き戻しのボタンに独自のチェックやメッセージを挟む SSJS ライブラリ customLib_SSJS.jss の customExtApplyOnClick() / customExtApproveOnClick() / customExtSendbackOnClick() / customExtDenyOnClick() / customExtPullbackOnClick() return false; で処理を中止。関連記事「Notes のフォームイベントは WEB フォームのどこに書くか」
承認バーに独自のボタンを足す 拡張スロット ccCustomExtButtons 空の実装で出荷されており、上書きして使います
フォームの上・中・下に独自の領域を足す ccCustomExt1 ~ ccCustomExt3 WEB フォームの値と連動させるときは customFormAfterPageLoad() で JavaScript を足す
左メニュー、ヘッダーのメニューに項目を足す(別システムへのリンクなど) ccCustomLeftSidebar1 ~ 4、ccCustomHeaderRightMenuItem1 ~ 2、ccCustomHeaderLeftNavItem / ccCustomHeaderRightNavItem
既存の Notes エージェントを、参照モードのボタンで実行する プロコード不要。外部システム連携(AGENT)の「アクションボタンとして表示」 表示する WEB フォーム・ステップ、承認者だけに見せる、確認メッセージを設定できます。関連記事「既存の Notes エージェント(LotusScript / Java)をワークフロー・ボタン・保存から呼び出す」

結果の確認

  • ボタン: 押したときだけ処理が動き、何も入力していない状態でも(検証の表示をオフにしていれば)動くこと
  • ダイアログ: 「開く」でダイアログが開き、確定で親の項目に値が入って閉じること。保存して開き直したとき、一時フィールドの値が文書に残っていないこと
  • 共通関数: 2 つ以上のフォームから同じ関数を呼べること。フォームビルダーのプレビューでは custom.js は読み込まれないので、実際の画面で確かめます

補足・注意

  • コンテンツ(HTML)コンポーネントに <script> を書いても、無害化されて実行されません。処理は、ボタンのカスタムロジック・計算値・条件表示・検証・logic に書きます
  • 自作のボタンから「保存して閉じる」まで一気に行う決まった方法はありません。保存の直後に処理が必要なときは、外部システム連携(AGENT)の「保存」「下書き保存」トリガや、サーバー側のフックを検討してください
  • 標準ボタンの表示条件を変える(例: 否認された文書だけに再申請ボタンを出す)のはプロコードの範囲です
  • フォームビルダーのプレビューでは cfGlobal が未定義です。先頭で typeof cfGlobal !== 'undefined' を確かめてください
  • ダイアログを「閉じる(×)」で閉じると、入力の破棄を確認するダイアログが出ます。確定ボタンからは、上の例のように「保存」を押したことにして閉じます

関連記事