サポート > リポジトリ > スクリプト > 入力チェック・整合性チェック スクリプト

複雑な入力チェックや整合性チェックをスクリプトで実現する方法を説明します。

入力チェック処理をスクリプトコードとして記述することができます。

図1 スクリプト記述欄

ここに書いた処理は、その他の(必須チェックや、文字数チェックといった設定で記述できる)チェックの後に実行されます。

正確には、入力チェックの最後の処理となります。

Designerでスクリプトを修正すると、開発機上のアプリケーションへ即座に反映されます。ビルド処理なしで修正を確認することができます。

スクリプト内では、モデル名に対応した「オブジェクト」を利用できます。

WagbyではWebフォームから入力された値は「プレゼンテーションモデル」が管理しています。

プレゼンテーションモデルの操作では、項目名の末尾に ".content" を付与することで、入力文字列を取得することができます。

次の例は、モデル schedule の日付項目 sch_date の入力が "H25" で始まる場合はエラーにする、というスクリプトです。

/* 日付を取り出す。*/
var s = 
    (schedule_p.schDate !== null) ? schedule_p.schDate.content : null; 
/* slice は JavaScript が提供する */
if (s !== null && s.slice(0,3)=="H25") { 
    var error = new Jfcerror();
    error.content = "平成25年はまだ入力できません。";
    p.errors.addJfcerror(error);
}

画面に表示するメッセージは次の3種類を利用することができます。

INFO

処理が正常に終了した場合のメッセージです。青枠にメッセージが表示されます。

var info = new Jfcinfo();
info.content="...";
p.errors.addJfcinfo(info);

WARN

警告メッセージです。黄色枠にメッセージが表示されます。

var warn = new Jfcwarn();
warn.content="...";
p.errors.addJfcwarn(warn);

ERROR

エラーメッセージです。赤枠にメッセージが表示されます。

var error = new Jfcerror();
error.content="...";
p.errors.addJfcerror(error);

国際化

メッセージの国際化にも対応しています。

エラーメッセージファイル $(DEVHOME)\customize\resources\myerrormsg_ja.properties.UTF8 に「キー=値」形式のメッセージを記述します。詳細は"メッセージの変更・国際化 > リソースファイルの編集"をお読みください。

リソースファイルは国際化に対応しています。英語版の場合は、myerrormsg_en.properties を用意してください。

次のコードでロケールに対応した適切なメッセージが出力されます。(この例では、キーに "error.original" という名称を使っています。)

p.errors.addJfcerror(errorManager.getJfcerror("error.original", p.locale));

エラーメッセージファイルにプレースホルダを指定することもできます。具体的には次のようになります。

var arrayOfStrings = Java.type("java.lang.String[]");
var obj = new arrayOfStrings(1);
obj[0] = "テストです。";
p.errors.addJfcerror(errorManager.getJfcerror("error.original", obj, p.locale));

例外 BusinessLogicException を利用する

Jfcerror などのクラスを使わず、例外 BusinessLogicException にエラーメッセージを含めることもできます。ここで設定したエラーメッセージが画面に表示されます。詳細...

throw new Packages.jp.jasminesoft.jfc.core.exception.BusinessLogicException("エラーメッセージ");

エラーではなく警告を使う場合は、JFCHelperUtils クラスを使います。次のようにしてください。

var JFCHelperUtils = Java.type("jp.jasminesoft.jfc.JFCHelperUtils");

var s = model1.item1;
if (s != null && s == '(エラーとしたい値)') {
    var warn = new Jfcwarn();
    warn.content="..."; /*警告メッセージ*/
    JFCHelperUtils.checkWarnedError(
        p, s, warn, "model1.item1", 
        "model1.item1.error.input.generic");
}

JFCHelperUtils.checkWarnedErrorメソッドの第一引数は p となります。第二引数は「入力された値」です。第三引数は警告オブジェクト(warn)です。第四引数は「モデルID.項目ID」としてください。第五引数は国際化対応時、エラーメッセージのリソースのキー名となります。通常は上記例のように「モデルID.項目ID.error.input.generic」としてください。

プレゼンテーションモデルの入力項目に errorcode という属性が用意されています。ここに何らかの値を設定すると、当該入力欄の背景を赤色とします。

モデルID「AAA」の繰り返しコンテナ「AAAM」に含まれる項目「AAAM/item1」の errorcode をセットするコードは次のとおりです。

var AAAMClass = Java.type("jp.jasminesoft.wagby.model.AAA_p.AAAM");
var Item1Class = Java.type("jp.jasminesoft.wagby.model.AAA_p.Item1");
var cont_ary = AAA_p.AAAM;
if (cont_ary !== null) {
  var values;
  for (var i=0; i<cont_ary.length; i++) {
    if (cont_ary[i].item1 === null) {
      values = new Item1Class();
      cont_ary[i].item1 = values;
    } else {
      values = cont_ary[i].item1;
    }
    values.errorcode = "ERROR";/* errorcode をセットする */
    var error = new Jfcerror();
    error.content = "ERROR";
    p.errors.addJfcerror(error);
  }
}

標準ではエラーメッセージに HTML タグを含めることはできません。これはセキュリティ対策のため、標準ではサニタイズ処理が有効となっているためです。

開発者は次のように sanitize フィールドをfalseとすることで、サニタイズ処理を無効にすることができます。

var error = new Jfcerror();
error.sanitize = false;
error.content = "<b>ERROR</b>";
p.errors.addJfcerror(error);

Webフォームからの入力ではなく、自動計算によって求められた値を使った「整合性チェック」を行うこともできます。この場合はストアモデルを用います。ストアモデルは画面から入力された文字列を適切な型(文字、数字、日付)に変換した値を保持します。また自動計算によって求められた値も保持します。

次の例は、親モデル Parent と子モデル Child (外部キーで関連する親子関係)において、親側の Parent に、子である Child モデルの数(COUNT)および、項目の最大値(MAX)が定義されているものとします。

具体的には Parent モデルの countOfChild 項目には計算式「COUNT(${child_lp})」が、maxOfChildItem1 項目には計算式「MAX(${child_lp.item1})」が、それぞれ定義されているものとします。

このとき、countOfChild 項目は2以上、maxOfChildItem1 項目が100以上というルールは次のように記述します。

/* Parent はストアモデル */
if (Parent.countOfChild < 2) {
    var error = new Jfcerror();
    error.content = "子モデルの数は2以上です。";
    p.errors.addJfcerror(error);
}
if (Parent.maxOfChildItem1 < 100) {
    var error = new Jfcerror();
    error.content = "子モデルitem1の最大値は100以上です。";
    p.errors.addJfcerror(error);
}
上記コードでもし Parent_p と表記すると、プレゼンテーションモデルを用います。プレゼンテーションモデルは画面から入力された値(文字列)を保持しますが、countOfChild 項目は計算式なので値が入っていません。よって、ここでプレゼンテーションモデルを用いるのは不適切、となります。

親子モデル関係において、子モデルの同時更新を有効にします。

このとき「親モデルに、必ず1件以上の子モデルが必要」という入力チェックは次のように記述できます。子モデルを Child と定義しています。

/* 子モデル名を Child と定義している */
var Child_ary = p.request.getAttribute("Child_ary");/*子モデル配列の取得*/
var count = Child_ary.length;
if (count < 1) {
    var error = new Jfcerror();
    error.content = "子モデルChildは1件以上、必要です。";
    p.errors.addJfcerror(error);
}

親子モデル同時更新機能では、入力チェック処理のタイミングで、対象となる子モデルの配列が、p.requestオブジェクトに格納されています。キー名は「子モデル名_ary」です。末尾に "_ary" をつけたキー名で、配列を取得できます。

これを取得し、配列の数をチェックすることで、子モデルの数を知ることができます。

なお、ここで取得した Child_ary はストアモデルです。

この例では Child の先頭は大文字となっています。モデル名が child と先頭が小文字の場合は、p.request.getAttribute("child_ary") となります。

親子モデル関係において、子モデルの同時更新を有効にします。

このとき「親モデルの出荷日と、各子モデルの納期日を比較する」というスクリプトを次のように記述することができます。

/*親モデルの出荷日と、子モデルの納期を比較する*/
var syukkabi = Parent.sdate;/*Parentはストアモデル*/
var Child_ary = p.request.getAttribute("Child_ary");
var count = Child_ary.length;
for (var i=0; i<count; i++) {
    var Child = Child_ary[i];/*Childもストアモデル*/
    var nouki = Child.nouki;/*syukkabiもnoukiもJavaScriptのDate型オブジェクトとして扱える*/
    if (syukkabi.getTime() > nouki.getTime()) {
        var error = new Jfcerror();
        error.content = (i+1)+"番目の納期は、出荷日よりも早い日になっています。";
        p.errors.addJfcerror(error);
    }
}

Parent ならびに Child_ary はストアモデルです。ストアモデルは文字列、数字、日付型を区別しているため、項目 sdate や nouki は日付型と認識されます。そのため JavaScript の日付オブジェクトとして操作できます。具体的には getTime() メソッドを利用した比較処理を行うことができます。

この例では Child の先頭は大文字となっています。モデル名が child と先頭が小文字の場合は、p.request.getAttribute("child_ary") となります。

customer モデルが最大、10件までしか登録できない、というルールを想定します。このチェックのためには、現在データベースに格納されている「件数」を知る必要があります。

入力チェックのスクリプトでデータベースを操作するためには、開発者の方で「セッション」を取得します。

入力チェックのスクリプトは、開発者が自らでセッションを取得する必要があります。

スクリプトの例を示します。

var HibernateUtil = Java.type("jp.jasminesoft.jfc.app.HibernateUtil");
var session = HibernateUtil.openSession();
try {
    var o = session.createSQLQuery(
           "SELECT COUNT(*) FROM \"customer\"").uniqueResult();
    if (o > 10) {
        var error = new Jfcerror();
        error.content = "10件以上のデータを登録することはできません。";
        p.errors.addJfcerror(error);
    }
} catch (e) {
    e.printStackTrace();
} finally {
    if (session !== null) {
        session.close();/*忘れないこと*/
    }
}
  • データベース操作のためのセッションオブジェクトは HibernateUtil.openSession() を使って取得します。
  • 取得したセッションは必ずクローズしてください。クローズを忘れると、利用できるデータベースセッションが不足し、運用途中で実行時エラーになります。
  • 上のスクリプトではテーブル customer の前後をダブルクォートで囲っています。お使いのデータベースによって、シングルクォートまたはダブルクォートのどちらかを使います。(内蔵DBであるHSQLDB利用時は、二重引用符で囲みます。)このため、開発機と本番機で異なるデータベースを用いる場合は、スクリプトファイルの変更も行う必要があるかも知れないということにご留意ください。
  • SQLは検索系でのみ利用してください。(*1)
  • 上記のサンプルコードは uniqueResult メソッドを使っているため、戻り値は常に1件である必要があります。複数件のレコードを返す SQL を記述した場合は list メソッドを使います。(詳細は Hibernate プログラミングを学んでください。) 次節で、EntityService を使って複数件を扱う例を説明します。
1. ここでは入力チェックを扱っているため、更新処理は生じないという前提で差し支えありません。Wagbyは更新時に独自のロックマネージャを使います。それを無視して直接、SQLで更新するとデータの整合性を保証できなくなります。更新を伴う場合は SQL ではなく Wagby が提供する EntityService を利用してください。

商品 (product) モデルを想定します。主キー項目 pkey は順序による自動採番とし、また、主キーではない項目「商品コード (pcode)」を持つとします。ここで、重複する商品コードを事前にチェックし、重複があった場合はエラーメッセージを表示するスクリプトを紹介します。

var screentype = p.request.getAttribute("__jfc_screen_type");/* SCREENTYPE 関数のこと */

var service = p.appctx.getBean("ProductEntityService");
var criteriaConverter = p.appctx.getBean("ProductCriteriaConverter");
var criteria = criteriaConverter.defaultCriteria();
var metaClass = Java.type("jp.jasminesoft.wagby.model.product.ProductMeta");
var meta = new metaClass();

criteria.eq(meta.pcode, product.pcode);/* pcode の重複を確認する。*/

var list = service.find(criteria);
if (list !== null && list.size() >= 1) {
    if (screentype === "update" && list.size() === 1) {
        var o = list.get(0);
        if (o.pkey === product.pkey) {
            /* 自分自身なのでエラーとしない */
            return;
        }
    }
    var error = new Jfcerror();
    error.content = "商品コード '"+product.pcode+"' が重複しています。";
    p.errors.addJfcerror(error);
}
  • クライテリア (criteria) は検索条件を扱います。詳細は"クライテリアを利用する"をお読みください。
  • 一意制約」の設定でも同じことができます。一意制約は、データベースにエラーを判定させる方法です。上のスクリプト方式はアプリケーションで判断するため、複雑な条件設定や、任意のエラーメッセージを用意できるといった拡張性があります。

ここでは model1 モデルのラジオボタン項目「有効・無効 (enabled)」がセットされたデータが1つだけかどうかをチェックする例を説明します。有効・無効(enabled)項目の値が "1" となっているデータが2件以上あった場合、エラーメッセージを表示して、編集画面に戻します。

なお、このチェック処理は、画面に表示されている分だけを対象としています。そのため、この一覧更新画面にすべてのデータが表示されるようになっていると仮定します。1ページに表示される編集対象データは「同時表示数のパターン」で指定することができます。
図2 一覧更新画面の入力チェック
入力チェックスクリプトのため、ここで値を書き換えることはできません。値の参照のみを行うことができます。

データベースコミット前

「コントローラ > 一覧更新 > データベースコミット前」を用意します。

function process() {
    var Jfcerror = Java.type("jp.jasminesoft.jfc.error.Jfcerror");
    var Item = Java.type("jp.jasminesoft.wagby.model.model1_ulp.Item");

    // Map key is primary key.
    // 編集中更新データのUlpモデルのItem
    // Map<String, jp.jasminesoft.wagby.model.model1_ulp.Item>
    var updateMap = p.pageMap.get("update_model1_ulp");
    // 編集中新規登録データのUlpモデルのItem
    // keyがnullのデータは既存データに紐づかない新規登録データ
    // keyがnullでないデータは、既存データに紐づくデータ
    // Map<String, List<jp.jasminesoft.wagby.model.model1_ulp.Item item>>
    var insertMap = p.pageMap.get("insert_model1_ulp");
    // 編集中削除データのUlpモデルのItem
    // Map<String, jp.jasminesoft.wagby.model.model1_ulp.Item>
    var deleteMap = p.pageMap.get("delete_model1_ulp");
    // 更新データの編集元のEntity
    // Map<String, Model1>
    var updateSrcMap = p.pageMap.get("update_src_model1_ulp");
    // 新規登録データの編集元のEntity
    // Map<String, List<Model1>>
    var insertSrcMap = p.pageMap.get("insert_src_model1_ulp");
    // 画面に表示されているデータに対応する編集中データのEntity
    // List<Model1>
    var datas = p.pageMap.get("datas_model1_ulp");
    // 画面に表示されているデータに対応する編集元データのEntity
    // List<Model1>
    var datasrc = p.pageMap.get("datasrc_model1_ulp");
    // 画面に表示されているデータのUlp
    // jp.jasminesoft.wagby.model.model1_ulp.Model1Ulp
    var _listp = p.pageMap.get("model1_ulp");

    var errormsg = "エラーが発生しました。有効・無効にて有効とするのは1か所のみとしてください。"
    
    var items = _listp.item;
    var enableditems = new Array();
    for (i=0 ; i < items.length ; i++) {
        var item = items[i];
        //print("item="+item);
        if (item.jfcdelete) {
            continue;
        }
        var enabled = getChoosedEnabled(item);
        //print ("item.enabled.id="+enabled.id)
        if (enabled.id === 1) {
            enableditems.push(item);
        }
    }
    if (enableditems.length > 1) {
        var error = new Jfcerror();
        error.content = errormsg;
        p.errors.addJfcerror(error);// 画面上部に表示されるエラーメッセージ。
        
        // 画面内のデータごとにエラーメッセージを表示するために、insertMap,updateMap
        // 内のItemにエラーメッセージをセットする。
        // do_setDataにて、これらのデータから表示用のデータにエラーメッセージがセットされるため。
        for (i=0 ; i < enableditems.length ; i++) {
            var item = enableditems[i];
            var jfcupdatetype = item.jfcupdatetype;
            var item1 = null;
            if (jfcupdatetype === "insert" || jfcupdatetype === "copy") {
                var itemlist = insertMap.get(item.jfcpkey);
                //print("itemlist="+itemlist)
                //print("item.pkeygroupnum="+item.jfcpkeygroupnum)
                if (itemlist !== null) {
                    item1 = itemlist.get(item.jfcpkeygroupnum-1);
                }
            } else if (jfcupdatetype === "update") {
                item1 = updateMap.get(item.jfcpkey);
                if (item1 === null) {// 未編集のデータであったため、新しい Item を用意する。
                    item1 = new Item(item);
                    updateMap.put(item.jfcpkey, item1);
                }
            }
            if (item1 !== null) {
                //print("item1="+item1)
                item1.jfcerror = errormsg;
            }
        }
    }
}

function getChoosedEnabled(item) {
    var enabledary = item.enabled;
    var enabled;
    for (j=0; j < enabledary.length; j++) {
        if (enabledary[j].choose) {
            enabled = enabledary[j];
            break;
        }
    }
    return enabled;
}
  • スクリプトの前半部分var xxx = p.pageMap.get("...")は、一覧更新処理を行っている UpdateListModel1Controller クラスの動作のために必要な内部の変数値を取得しています。スクリプト内ですべての変数を利用しているわけではありませんが、このような変数が利用できるということを示すため、すべての変数を用意しています。詳細は各行のコメントをお読みください。
  • 画面に表示された1ページのデータをvar _listp = p.pageMap.get("model1_ulp")にて取得しています。接尾語に "_ulp" が付与されたプレゼンテーションモデルは一覧更新画面のみで利用できるもので、現在表示されているページのデータが格納されています。
  • 保存ボタン押下時に、UpdateListModel1Controllerクラスのdo_updateメソッドが呼び出されます。この処理で、HttpServletRequestに格納された修正データが変数 _listp に反映されるようになっているため、上のスクリプトで取得した _listp で編集データとして取得することができるようになっています。
  • 変数 _listp はさらに内部で複数の行データを保持しています。var items = _listp.item;とすることで、この行データを配列として取得できます。この実態は jp.jasminesoft.wagby.model.model1_ulp.Item クラスです。
  • スクリプトの中盤では、取得した items を for ループで一件ずつ処理しています。ここで item.jfcdelete が true の場合とは、削除のチェックボックスがチェックされているデータです。今回は対象としないようにしています。
  • getChoosedEnabled関数は、本スクリプトの後半部分に定義しています。item から enabled 項目の値を取得します。enabled項目はラジオボタンとなっているため、その戻り値は jp.jasminesoft.wagby.model.model1_ulp.Enabled の配列です。この配列内から enabled.choosed が trueとなっているデータを見つけます。具体的には enabled.id の値が 1 の場合、ラジオボタンで "有効" が選択されているとみなしているため、enableditems に item を格納するようにしています。
  • enableditems.length のサイズが 1 より大きい場合、"有効" が選択されたラジオボタンが 2 つ以上あるため、エラーとしています。(今回のエラーチェックの要件となります。)
  • スクリプトの後半で、エラーのあったデータに対して、エラーメッセージをセットしています。このエラーメッセージは _listp に格納された item にセットするのではなく、画面表示用のデータを格納するための insertMap および updateMap 変数を用いる必要があります。
  • _listp内の item の jfcupdatetype を使うと、このデータが更新、新規登録、コピー登録のいずれかを知ることができます。
  • また item の jfcpkey は主キーが格納されています。この値をキーに insertMap や updateMap から表示用の item を取得します。
  • insertMap はコピー登録にも対応しています。コピー登録の場合、一つのデータに対して複数のコピー登録が可能であるため、insertMapには List<Item> が格納されます。pkeygroupnum の値を使って、何番目のデータと紐づいているかを知ることができます。
  • これらの操作を行なって insertMap および updateMap から対応する Item を取得し、エラーメッセージをセットします。
  • updateMap に(主キーに対応する)Item が存在しなかった場合は、未編集のデータであることを意味します。上のスクリプトでは未編集のデータだった場合は新しい Item を生成し、updateMap にセットしています。この場合、画面上は未編集であっても、このスクリプトによって編集中として扱われるようになります。

更新の実行

「コントローラ > 一覧更新 > 更新の実行」を用意します。

上で説明した「データベースコミット前」のスクリプトで、insertMap や updateMap に直接、エラーメッセージをセットしていました。「更新の実行」スクリプトで、これらのエラーメッセージを消去しておきます。(消去しないとエラーメッセージが残ってしまうためです。)

function process() {
    var Jfcerror = Java.type("jp.jasminesoft.jfc.error.Jfcerror");

    // Map key is primary key.
    // 編集中更新データのUlpモデルのItem
    // Map<String, jp.jasminesoft.wagby.model.model1_ulp.Item>
    var updateMap = p.pageMap.get("update_model1_ulp");
    // 編集中新規登録データのUlpモデルのItem
    // keyがnullのデータは既存データに紐づかない新規登録データ
    // keyがnullでないデータは、既存データに紐づくデータ
    // Map<String, List<jp.jasminesoft.wagby.model.model1_ulp.Item item>>
    var insertMap = p.pageMap.get("insert_model1_ulp");
    // 編集中削除データのUlpモデルのItem
    // Map<String, jp.jasminesoft.wagby.model.model1_ulp.Item>
    var deleteMap = p.pageMap.get("delete_model1_ulp");
    // 更新データの編集元のEntity
    // Map<String, Model1>
    var updateSrcMap = p.pageMap.get("update_src_model1_ulp");
    // 新規登録データの編集元のEntity
    // Map<String, List<Model1>>
    var insertSrcMap = p.pageMap.get("insert_src_model1_ulp");
    // 画面に表示されているデータに対応する編集中データのEntity
    // List<Model1>
    var datas = p.pageMap.get("datas_model1_ulp");
    // 画面に表示されているデータに対応する編集元データのEntity
    // List<Model1>
    var datasrc = p.pageMap.get("datasrc_model1_ulp");
    // 画面に表示されているデータのUlp
    // jp.jasminesoft.wagby.model.model1_ulp.Model1Ulp
    var _listp = p.pageMap.get("model1_ulp");

    var errormsg = "エラーが発生しました。有効・無効にて有効とするのは1か所のみとしてください。"
    
    // insertMap, updateMapからエラーメッセージを削除する。
    // エラーメッセージが残っていると、修正してもエラー状態となり、データベース保存への
    // トランザクションが実行されないため。
    var updateitems = updateMap.values().toArray();
    for (i=0 ; i < updateitems.length ; i++) {
        var item = updateitems[i];
        //print("update item="+item);
        if (item.sizeJfcerror() == 1 && item.getJfcerror(0) === errormsg) {
            item.clearJfcerror();
        }
    }
    
    var insertitemlists = insertMap.values().toArray();
    for (i=0; i < insertitemlists.length; i++) {
        var itemlist = insertitemlists[i]
        if (itemlist === null) {
            continue;
        }
        for (j=0; j < itemlist.size(); j++) {
            var item = itemlis.get(j);
            //print("insert item="+item);
            if (item.sizeJfcerror() == 1 && item.getJfcerror(0) === errormsg) {
                item.clearJfcerror();
            }
        }
    }
}
  • このスクリプトでは insertMap や updateMap から Item を取得し、今回表示したエラーメッセージと同じ文言が設定されている場合に限り、エラーメッセージをクリアする処理を行っています。クリア処理は item に用意された clearJfcerror メソッドを呼び出します。

よりシンプルなスクリプト

これまでの説明は、updateMap や insertMap といった(一覧更新画面の内部で利用している)表示用データを操作していました。次に紹介するスクリプトは、これらの内部変数を使わないパターンです。

updateMap や insertMap を意識しないでよいという要件であれば、こちらの方式を推奨します。

データベースコミット前

function process() {
   var Jfcerror = Java.type("jp.jasminesoft.jfc.error.Jfcerror");

   // 画面に表示されているデータのUlp
   // jp.jasminesoft.wagby.model.model1_ulp.Model1Ulp
   var _listp = p.pageMap.get("model1_ulp");

   var errormsg = "エラーが発生しました。有効・無効にて有効とするのは1か所のみとしてください。"

   var items = _listp.item;
   var count = 0;
   for (i=0 ; i < items.length ; i++) {
       var item = items[i];
       //print("item="+item);
       if (item.jfcdelete) {
           continue;
       }
       var enabled = getChoosedEnabled(item);
       //print("item.enabled.id="+enabled.id);
       if (enabled.id === 1) {
           count++;
       }
   }
   if (count > 1) {
       var error = new Jfcerror();
       error.content = errormsg;
       p.errors.addJfcerror(error);// 画面上部に表示されるエラーメッセージ。
   }
}

function getChoosedEnabled(item) {
   var enabledary = item.enabled;
   var enabled;
   for (j=0; j < enabledary.length; j++) {
       if (enabledary[j].choose) {
           enabled = enabledary[j];
           break;
       }
   }
   return enabled;
}

更新の実行

function process() {
   // 画面に表示されているデータのUlp
   // jp.jasminesoft.wagby.model.model1_ulp.Model1Ulp
   var _listp = p.request.getAttribute("model1_ulp");

   var errormsg = "エラーが発生しました。有効・無効にて有効とするのは1か所のみとしてください。";

   // p.request.getAttribute("__jfc_jfcerrors")をチェックして「データベースコミット前」のスクリプトで
   // errormsgのエラーメッセージが設定されたかどうかをチェックする。
   var jfcerrors = p.request.getAttribute("__jfc_jfcerrors");
   var isSetErrorMessage = false;
   if (jfcerrors !== null) {
       var existerrmsg = jfcerrors.jfcerror;
       for (var i=0; i<existerrmsg.length; i++) {
           var error = existerrmsg[i];
           if (error.content === errormsg) {
               isSetErrorMessage = true;
               break;
           }
       }
   }

   if (isSetErrorMessage) { // エラーメッセージが設定されていた
       var items = _listp.item;
       var enableditems = new Array();
       for (i=0 ; i < items.length ; i++) {
           var item = items[i];
           //print("item="+item);
           if (item.jfcdelete) {
               continue;
           }
           var enabled = getChoosedEnabled(item);
           //print("item.enabled.id="+enabled.id)
           if (enabled.id === 1) {
               item.jfcerror = errormsg;// 同じエラーメッセージを各データにもセットする。
           }
       }
   }
}

function getChoosedEnabled(item) {
   var enabledary = item.enabled;
   var enabled;
   for (j=0; j < enabledary.length; j++) {
       if (enabledary[j].choose) {
           enabled = enabledary[j];
           break;
       }
   }
   return enabled;
}

前節で説明したスクリプトは、画面に表示されているデータのみを対象にしていました。ここでは(画面に表示されていない分も含めた)データの入力チェックを行うスクリプトを紹介します。

図3 一覧更新画面の入力チェック
入力チェックスクリプトのため、ここで値を書き換えることはできません。値の参照のみを行うことができます。

データベースコミット前

「コントローラ > 一覧更新 > データベースコミット前」を用意します。

function process() {
   var Jfcerror = Java.type("jp.jasminesoft.jfc.error.Jfcerror");
   var finderContext = p.appctx.getBean("UpdateListModel1FinderContext");
   var entityService = p.appctx.getBean("Model1EntityService");
   var results = entityService.find(finderContext);
   var count = 0;
   for (i=0; i<results.size(); i++) {
       var entity = results.get(i);
       //print("results="+entity);
       if (entity.enabled === 1) {
           count++;
       }
   }
   if (count > 1) {
       var error = new Jfcerror();
       error.content = "エラーが発生しました。有効・無効にて有効とするのは1か所のみとしてください。"
       p.errors.addJfcerror(error);
   }
}
  • このスクリプトではデータベースを操作して全データをチェックします。画面上のデータに依存しない代わりに、画面上の各行へのエラーメッセージのセットは行なっていません。