Formaでのスクリプト開発生産性向上

先日開催されました技術者交流会にて、クライアントサイドスクリプトを利用したFormaDesignerの画面開発が難しいという声を多くいただきました。

そこで、今回のブログ記事では、交流会の場で挙がった課題を解決させるためのTipsと新機能をご紹介します。

 

目次

  1. スクリプトの履歴管理・共通化を実現したい
  2. 画面アイテムを対象にした処理を作成したい
  3. スクリプトの実行順を制御したい
  4. よく利用するアクションはノンプログラミングで実現したい

 

1. スクリプトの履歴管理・共通化を実現したい

 

■ FormaDesignerの開発における履歴管理・共通化の課題

従来のスクラッチ開発をベースとしたシステム開発では、作成したソースファイルを統合開発環境のプロジェクトの構成にて管理します。

プロジェクト形式に整理されたソースファイルは、バージョン管理システムに保存され、各リリースごとの差分が簡単に把握できます。

また、各画面にて共通となる処理については、同じ内容を各画面ごとに管理するのではなく、共通のソースファイルとして切り出します。

 

一方、FormaDesignerを利用した開発にてスクリプトを組み込む場合、スクリプト記述用の画面アイテムのプロパティにソースコードを直接記述します。

プロパティに記述されたソースコードの実体は、各フォームごとの定義情報が格納されたjsonファイルに出力されます。

jsonファイルにはスクリプトだけでなく、デザイナーで設定したあらゆるプロパティが格納されるため、開発したスクリプトのソースファイルとして扱うことはできません。

 

そのため、FormaDesignerの開発では、従来のスクラッチ開発の手法の利用が難しい点があります。

  1. ソースファイルとして切り出せないため、バージョン管理ができない。
  2. 個々のフォームのにスクリプトが格納されるため、ソースファイルの共通化が行えない。

 

次の章では、これらの課題を解決するための「テンプレートHTML」の活用方法を説明します。

 

■ テンプレートHTMLによるスクリプトの外出し・共通化

FormaDesignerのアプリケーションが実行される画面は、テンプレートHTMLというベースとなるHTMLファイル上に、各画面アイテムのHTMLが配置されて生成される仕組みになっています。

各画面アイテムのインスタンスにて共通した処理となるスクリプトについてはHTMLサイズ削減のため外部ファイルとして外出しで管理され、ベースとなるテンプレートHTMLからscriptタグを通して読み込まれます。

パブリックストレージ/forma/html_template/template.html

 

上記のテンプレートHTMLはパブリックストレージ上に配置されておりますが、こちらをカスタマイズし、scriptタグを記述することが可能です。

scriptタグを記述することで、アプリケーションの実行画面にて任意のスクリプトファイルを読み込ませることができます。

上記の仕組みを利用して、スクリプト記述用の画面アイテムのプロパティから、外部ファイルに外出しすることで、スクリプトのソースファイルについてもバージョン管理の対象とすることが可能です。

また、テンプレートHTMLで読み込まれるスクリプトファイルは全アプリケーションに適用されるため、ソースファイルの共通化も実現できます。

【注意事項1】
IM-FormaDesigner 2014 Winterアップデートより、
テンプレートHTMLファイルは初回読み込み時にキャッシュされる動作となっておりますので、テンプレートHTMLをカスタマイズされた際は再起動もしくは「HTMLテンプレートキャッシュ削除」ジョブを実行していただく必要がございます。

【注意事項2】
テンプレートHTMLのファイルは製品モジュールのソースファイルに該当しますので、今後のアップデートにて修正される可能性があります。
アップデート時には製品側で修正された内容をカスタマイズされたテンプレートHTMLファイルにマージしていただく必要がございます。

 

テンプレートHTMLの共有範囲の限定

テンプレートHTMLは通常1テナント単位にて管理されており、テナント上の全てのアプリケーションで共有されますが、共有範囲を限定することも可能です。

各アプリケーション、各フォームごとに固有のテンプレートHTMLを指定可能です。
下記のディレクトリに配置することで、固有のテンプレートHTMLが読み込まれます。

  1. アプリケーション固有のテンプレート
    パブリックストレージ/forma/html_template/%アプリケーションID%/%アプリケーションID%.html

  2. フォーム固有のテンプレート
    パブリックストレージ/forma/html_template/%アプリケーションID%/%フォームID%/%フォームID%.html

各テンプレートの読み込みの優先順位は、下記の通りです。
フォーム固有のテンプレート > アプリケーション固有のテンプレート > テナント固有のテンプレート

【注意事項1】
IM-FormaDesigner 2014 Winterアップデートより、
テンプレートHTMLファイルは初回読み込み時にキャッシュされる動作となっておりますので、テンプレートHTMLをカスタマイズされた際は再起動もしくは「HTMLテンプレートキャッシュ削除」ジョブを実行していただく必要がございます。

【注意事項2】
テンプレートHTMLのファイルは製品モジュールのソースファイルに該当しますので、今後のアップデートにて修正される可能性があります。
アップデート時には製品側で修正された内容をカスタマイズされたテンプレートHTMLファイルにマージしていただく必要がございます。

 

チュートリアル

ここでは、実際にアプリケーション固有のテンプレートを使って、外部ファイルで定義したスクリプトをアプリケーションに組み込む手順をご紹介します。

今回は例として、サンプルアプリケーション「稟議書」の稟議件名フィールドに入力された値がIM-Workflowの案件名に連動されるスクリプトを組み込みます。

チュートリアル サンプルモジュール

1. eBuilderのモジュールプロジェクトを作成します。

スクリプトファイルとテンプレートHTMLを管理するためのモジュールプロジェクトを作成します。

モジュールの依存関係には、formaモジュール(モジュールID : jp.co.intra_mart.forma)を指定します。

 

詳しくは、
「intra-mart e Builder for Accel Platform / ユーザ操作ガイド モジュール・プロジェクト作成」
をご参照ください。

 

2. アプリケーションに組み込むためのスクリプトを作成します。

モジュールプロジェクト上にテンプレートに組み込むjsファイルを作成し、任意の処理を記述します。

 

3. アプリケーション固有のテンプレートを作成します。

(1)デバッグサーバのパブリックストレージからテナント固有のテンプレートHTMLを取得します。

テナント固有のテンプレート.png

 

(2)取得したテンプレートHTMLをリネームし、モジュールプロジェクトのストレージ上にアプリケーション固有のテンプレートとして配置します。

アプリケーション固有のテンプレート.png

 

4. テンプレートHTMLをカスタマイズし、2で作成したJsファイルが読み込まれるようにscriptタグで指定します。

Jsファイル組み込み.png

 

5. モジュールプロジェクトをビルドし、デバッグサーバへデプロイします。

 

6. アプリ実行画面を表示し、スクリプトが正しく動作することを確認します。

(1) 稟議書アプリケーションの画面にて、稟議件名を入力します。

 

(2) IM-Workflowの申請画面を表示し、稟議件名が案件名に連動されていることを確認します。

 

2. 画面アイテムを対象にした処理を作成したい

各アイテムの仕様が公開されていないため、各アイテムを対象にした処理を記述する際にブラウザの開発者ツールなどで各アイテムのDOM構造を調査する必要があります。

APIを利用して処理を記述することで、各アイテムごとの仕様を調査せずに、対象のアイテムを操作することが可能です。

入力アイテムから値を取得するAPI

入力アイテムから値を取得するAPI

アイテム名API
文字列formaItems.product_72_textbox.getItemData.%フィールド識別ID%
複数行文字列formaItems.product_72_textarea.getItemData.%フィールド識別ID%
数値formaItems.product_72_number.getItemData.%フィールド識別ID%
隠しパラメータformaItems.product_72_hidden.getItemData.%フィールド識別ID%
日付formaItems.product_72_calendar.getItemData.%フィールド識別ID%
期間formaItems.product_72_terms.getItemData.%フィールド識別ID%
一覧選択(v72)formaItems.product_72_itemSelect.getItemData.%フィールド識別ID%
チェックボックス(v72)formaItems.product_72_checkbox.getItemData.%フィールド識別ID%
セレクトボックス(v72)formaItems.product_72_selectbox.getItemData.%フィールド識別ID%
リストボックス(v72)formaItems.product_72_listbox.getItemData.%フィールド識別ID%
ユーザ選択formaItems.product_72_userSelect.getItemData.%フィールド識別ID%
組織選択formaItems.product_72_departmentSelect.getItemData.%フィールド識別ID%
組織・役職選択formaItems.product_72_departmentPostSelect.getItemData.%フィールド識別ID%
所属組織選択formaItems.product_72_affiliationSelect.getItemData.%フィールド識別ID%

テーブルアイテムから値を取得するAPI

アイテム名API
グリッドテーブルformaItems.product_80_gridtable.getItemData.%テーブル識別ID%(String rowId,Array inputIdList)

 

(サンプルコード) 入力アイテムから値を取得する

文字列 入力値の取得

(function($){
var result = formaItems.product_72_textbox.getItemData.%フィールド識別ID%();
alert(result);
})(jQuery);

リストボックス(v72) 入力値の取得

(function($){
var result = formaItems.product_72_listbox.getItemData.%フィールド識別ID%();
var valueArray = result.split( ',' );
for(var i=0; i<valueArray.length; i++){
alert(valueArray[i]);
}
})(jQuery);

グリッドテーブル 全行取得

(function($){
var rowId = "";
var inputIdList = [];
inputIdList[0] = "%フィールド識別ID%";
var result = formaItems.product_80_gridtable.getItemData.%テーブル識別ID%(rowId, inputIdList);
for(var i=0; i<result.length; i++){
alert(result[i].%フィールド識別ID%);
}
})(jQuery);

グリッドテーブル 特定行取得

(function($){
var rowId = 行数;
var inputIdList = [];
inputIdList[0] = "%フィールド識別ID";
var result = formaItems.product_80_gridtable.getItemData.%テーブル識別ID%(rowId, inputIdList);
alert(result[0].%フィールド識別ID%);
})(jQuery);

 

入力アイテムに値を反映するAPI

入力アイテムに値を反映するAPI

アイテム名API備考
文字列formaItems.product_72_textbox.setItemData.%フィールド識別ID%(Object arg) 
複数行文字列formaItems.product_72_textarea.setItemData.%フィールド識別ID%(Object arg) 
数値formaItems.product_72_number.setItemData.%フィールド識別ID%(Object arg) 
日付formaItems.product_72_calendar.setItemData.%フィールド識別ID%(Object arg) 
期間formaItems.product_72_terms.setItemData.%フィールド識別ID%(Object arg) 
隠しパラメータformaItems.product_72_hidden.setItemData.%フィールド識別ID%(Object arg) 
一覧選択(v72)formaItems.product_72_itemSelect.setItemData.%フィールド識別ID%(Object arg) 
チェックボックス(v72)formaItems.product_72_checkbox.setItemData.%フィールド識別ID%(Object arg)複数要素指定はカンマ区切りの文字列。送信値に一致する行が選択される。
セレクトボックス(v72)formaItems.product_72_selectbox.setItemData.%フィールド識別ID%(Object arg)送信値に一致する行が選択される。
リストボックス(v72)formaItems.product_72_listbox.setItemData.%フィールド識別ID%(Object arg)複数要素指定はカンマ区切りの文字列。送信値に一致する行が選択される。
ユーザ選択formaItems.product_72_userSelect.setItemData.%フィールド識別ID%(Object arg) 
組織選択formaItems.product_72_departmentSelect.setItemData.%フィールド識別ID%(Object arg) 
組織・役職選択formaItems.product_72_departmentPostSelect.setItemData.%フィールド識別ID%(Object arg) 

 

引数のargは、下記の構造のオブジェクトで指定してください。

入力値は、アイテムのデータ型に合わせてセットしてください。文字列型(String)・数値型(Number型)・日付型(Date型)・タイムスタンプ型(Date型)。

var args = {};
args.data = {};
args.data.%フィールド識別ID% = "入力値";

テーブルアイテムに値を反映するAPI

アイテム名API
グリッドテーブルformaItems.product_80_gridtable.setItemData.%テーブル識別ID%(Object args, Object option);

 

全行更新の場合、引数のarg, optionは、それぞれ下記の構造のオブジェクトで指定してください。

var args = {};
args.data = {};
args.data.%テーブル識別ID% = [];
for(var i=0; i<valueArray.length; i++){
args.data.%テーブル識別ID%[i] = {};
args.data.%テーブル識別ID%[i].%フィールド識別ID% = valueArray[i];
}
var option = {};

 

特定行更新の場合、引数のarg, optionは、それぞれ下記の構造のオブジェクトで指定してください。
グリッドテーブルの場合は、削除された行数についても行数の計算にて考慮する必要があります。

var args = {};
args.data = {};
args.data.%テーブル識別ID% = [];
args.data.%テーブル識別ID%[0] = {};
args.data.%テーブル識別ID%[0].%フィールド識別ID% = "入力値";
var option = {};
option.indexKey = 行数;

 

(サンプルコード) 入力アイテムに値を反映する

文字列 入力値の反映

(function($){
var args = {};
args.data = {};
args.data.%フィールド識別ID% = "入力値";
formaItems.product_72_textbox.setItemData.%フィールド識別ID%(args);
})(jQuery);

日付 入力値の反映

(function($){
var args = {};
args.data = {};
args.data.%フィールド識別ID% = new Date();
formaItems.product_72_calendar.setItemData.%フィールド識別ID%(args);
})(jQuery);

リストボックス(v72) 入力値の反映

(function($){
var args = {};
args.data = {};
args.data.%フィールド識別ID% = "入力値1,入力値2,入力値3";
formaItems.product_72_listbox.setItemData.%フィールド識別ID%(args);
})(jQuery);

グリッドテーブル 全行反映

(function($){
var args = {};
args.data = {};
args.data.%テーブル識別ID% = [];
for(var i=0; i<valueArray.length; i++){
args.data.%テーブル識別ID%.%フィールド識別ID% = valueArray[i];
}
var option = {};
formaItems.product_80_gridtable.setItemData.%テーブル識別ID%(args, option);
})(jQuery);

グリッドテーブル 特定行反映

(function($){
var args = {};
args.data = {};
args.data.%テーブル識別ID% = [];
args.data.%テーブル識別ID%[0] = {};
args.data.%テーブル識別ID%[0].%フィールド識別ID% = "入力値";
var option = {};
option.indexKey = 行数;
formaItems.product_80_gridtable.setItemData.%テーブル識別ID%(args, option);
})(jQuery);

 

入力アイテムの入力不可・入力可状態を切り替えるためのAPI

入力アイテムの入力不可・入力可状態を切り替えるためのAPI

アイテム名API
文字列formaItems.product_72_textbox.changeInputMode(Object controlSetting)
複数行文字列formaItems.product_72_textarea.changeInputMode(Object controlSetting)
数値formaItems.product_72_number.changeInputMode(Object controlSetting)
日付formaItems.product_72_calendar.changeInputMode(Object controlSetting)
期間formaItems.product_72_terms.changeInputMode(Object controlSetting)
一覧選択(v72)formaItems.product_72_itemSelect.changeInputMode(Object controlSetting)
チェックボックス(v72)formaItems.product_72_checkbox.changeInputMode(Object controlSetting)
セレクトボックス(v72)formaItems.product_72_selectbox.changeInputMode(Object controlSetting)
リストボックス(v72)formaItems.product_72_listbox.changeInputMode(Object controlSetting)
ユーザ選択formaItems.product_72_userSelect.changeInputMode(Object controlSetting)
組織選択formaItems.product_72_departmentSelect.changeInputMode(Object controlSetting)
組織・役職選択formaItems.product_72_departmentPostSelect.changeInputMode(Object controlSetting)
所属組織選択formaItems.product_72_affiliationSelect.changeInputMode(Object controlSetting)

 

引数のcontrolSettingは、下記の構造のオブジェクトで指定してください。

var controlSetting = {};
controlSetting.mode = "valid"; // 入力可 valid・入力不可 invalid
controlSetting.inputId = "%フィールド識別ID%";

テーブルアイテムの入力不可・入力可状態を切り替えるためのAPI

アイテム名API
グリッドテーブルformaItems.product_80_gridtable.changeInputMode(Object controlSetting)

 

テーブル全体の状態を切り替える場合、引数のcontrolSettingは、下記の構造のオブジェクトで指定してください。

var controlSetting = {};
controlSetting.tableId = "%テーブル識別ID%";
controlSetting.inputId = ""; // 空文字を指定
controlSetting.mode = "valid"; // 入力可 valid・入力不可 invalid

 

特定列の状態を切り替える場合、引数のcontrolSettingは、下記の構造のオブジェクトで指定してください。
列タイプについては、文字列(textbox), 数値(number),日付(calendar),一覧選択(itemSelect),セレクトボックス(selectbox)を指定してください。

var controlSetting = {};
controlSetting.tableId = "%テーブル識別ID%";
controlSetting.inputId = "%フィールド識別ID%";
controlSetting.inputItemType = "textbox"; // 列タイプを指定
controlSetting.mode = "valid"; // 入力可 valid・入力不可 invalid

 

(サンプルコード) 入力アイテムの入力不可・入力可状態を切り替える

文字列 入力不可

(function($){
var controlSetting = {};
controlSetting.mode = "invalid";
controlSetting.inputId = "%フィールド識別ID%";
formaItems.product_72_textbox.changeInputMode(controlSetting);
})(jQuery);

グリッドテーブル テーブル全体入力不可

(function($){
var controlSetting = {};
controlSetting.tableId = "%テーブル識別ID%";
controlSetting.mode = "invalid";
controlSetting.inputId = '';
window.formaItems.product_80_gridtable.changeInputMode(controlSetting);
})(jQuery);

グリッドテーブル 特定列の入力不可

var controlSetting = {};
controlSetting.tableId = "%テーブル識別ID%";
controlSetting.mode = "invalid";
controlSetting.inputId = "%フィールド識別ID%";
controlSetting.inputItemType = "textbox";
formaItems.product_80_gridtable.changeInputMode(controlSetting);

 

3. スクリプトの実行順を制御したい

各画面アイテム自身のスクリプト処理とアドオンで追加したスクリプトの間で実行順を制御するのが、難しいという声をいくつかいただきました。

実行順はスクリプトの読み込み、すなわちアイテムの読み込み順にて定義されます。アイテムの読み込み順は、デザイナーのコンテキストメニューにて「前面へ移動」「背面へ移動」を行うことで変更できます。

 

アイテムの固有処理後に任意のスクリプトを実行

テンプレートHTML上で、form_areaのdivタグより後方にてscriptタグを配置していただき、スクリプトファイル内に$(document).ready(function(){});を定義し、その関数の内部に処理を記述していただくことで、スクリプトの内容が各アイテム固有の処理後に実行されます。

 

4. よく利用するアクションはノンプログラミングで実現したい

複雑なプログラム処理でなく、業務で利用頻度の高いアクションについては設定だけで実現したいという声をいくつかいただきました。

アクション設定機能を利用すると、アイテムの表示・非表示,入力可・入力不可の制御,クエリの実行については設定だけで実現できます。

詳しくは、

「IM-BIS for Accel Platform / 業務管理者 操作ガイド 7.10.アクションを設定する」

をご参照ください。

【注意事項】
アクション設定機能は、IM-BISがインストールされた環境でのみ利用可能です。
また、IM-BIS 2014 Winter Patch01以降で利用できる機能となります。