休暇申請管理プロセスのサンプルを使用して、UI デザイナーでのフォーム活用方法と送信データのエラーチェックの追加方法を学習します。
はじめに
あなたは Bonita BPM 7.5.0 以降 を使用してシンプルな休暇申請管理プロセスをデザインします:
まず最初に、プロセスのワイヤフレームを描画します。Bonita Studio で、下図に示すように、プールレベルで起こる新しい休暇申請の起案(インスタンス化)の後に、簡単な検証タスクを追加し、プールの名前を「休暇申請管理」に、レーンの名前を「マネージャ」に変更します:
次に、プロセス インスタンスが進行中しているときに休暇申請のデータを保持し、インスタンスがアーカイブされたときにそれを格納するビジネス オブジェクトを定義します。Bonita Studio のメニューオプションで、開発 > ビジネス データモデル > 管理… の順に移動し、 「LeaveRequest」と命名した次の4つの属性を持つビジネス オブジェクトを追加します:
- startDate:DATE ONLY、休暇開始日
- endDate:DATE ONLY、休暇終了日
- nbDays:INTEGER、休暇日数
- type:TEXT、休暇の種類(年次休暇、リフレッシュ休暇、…)
このビジネス・オブジェクトが各プロセスインスタンスでインスタンス化されることを可能にするためには、プロセスレベルのビジネス変数を作成します。そのためには、プールレベルの「データ」パネルで leaveRequest と命名したビジネス変数を定義し、ビジネス オブジェクトとして LeaveRequest を選択します。
その後、プロセスが起案フォームに必要な情報を取得するために、コントラクトを作成します。「実行」ペイン > 「コントラクト」タブに移動して「データから追加…」ボタンをクリックし、既存のビジネス変数から入力コントラクトを生成します。「ビジネス変数」オプションと leaveRequest 変数を選択します。COMPLEX 型の入力コントラクトが作成され、 leaveRequest のビジネス変数にマッピングされます。
コントラクトの各エントリは、下図に示すようにビジネス オブジェクトのプロパティにバインドされます:
また、「制約」タブをクリックし、入力コントラクトに制約を追加することができます。この制約の追加は、後のセクションで説明します。
プロセス、ビジネスデータの管理、コントラクトの詳細については、効率的なBPMアプリケーションの設計:初心者のためのプロセス・ベースのガイドを参照してください。
ユーザーが新しい要求を開始する起案フォームをこのコントラクトにベースに生成するには、「起案フォーム 」タブに移動し、右端のペンアイコンをクリックします。これで、UI デザイナーが開き、フォームが表示されます。デフォルトで生成されたフォームには、コントラクトと一致する次の4つのウィジェットを内包したフォームコンテナ が含まれています:
- startDate のための日付ピッカーウィジェット
- endDate のための日付ピッカーウィジェット
- nbDays のための日数の入力ウィジェット
- type のためのテキストの入力ウィジェット
これらは下図のように表示されます:
これから自動生成されたフォームを日本語仕様に変更します。
次のようにタイトルと入力フィールドの「ラベル」をに日本語に変更します。
- Leave Request > 休暇申請
- Start Date > 開始日
- End Date > 終了日
- Nb Days > 取得休暇日数
- Type > 種類
開始日と終了日の次のプロパティを変更します。
- 「テクニカルな日付書式」: MM/dd/yyyy > yyyy/MM/dd
- 「日付のプレース ホルダー」: Enter a date (mm/dd/yyyy) > 日付 (yyyy/mm/dd) を入力します
- 「今日のボタンのラベル」: Today > 今日
UI デザイナーの「プレビュー」ボタンをクリックすることによって、このフォームがデプロイされ、どのように見えるかを下図に示すように確認することができます:
コントラクトの基本的なエラーチェックと制約
上図を見て、あなたは次のことに気づくと思います。
- すべてのフィールドのラベルには、(コントラクトによって定義された)入力必須を示す赤い星(*)がある
- 赤い星でマークされたフィールドは、すべて入力されるまで Submit ボタンは無効のままになりグレーアウトされている
入力制約の1つが無効の場合は、エラーメッセージが入力フィールドの下に表示されます。この例では、入力コントラクトだけか必須となるため、フィールドを編集しリセットした場合、エラーメッセージが下図のように表示されます:
すべてのフィールドに値を持っていたら、フォームは、プロセスによってコントラクトがエラーチェックされ submit することができ、新しいプロセス インスタンスを開始することができます。
コントラクトのより高度なエラーチェック
入力エラー情報の可視化
さて、ユーザに入力が無効であることを赤い枠線で警告するためには、AngularJS の「フォーム コントロール プロパティ」を使用する必要があります。
AngularJS の $form
フォームコンテナの内部では、AngularJS は $form と呼ばれる特殊な変数を提供します。
この変数は、現在のフォームコンテナの入力、選択、テキストエリアの検証状態を保持します。
以下は、この機能の目的を説明している AngularJS のドキュメントサイトからの抜粋です。
AngularJS のビューポイントでは、フォームは互いに関連するコントロールをグループ化するためにコントロールのコレクションである。
フォームとコントロールは、検証サービスを提供するので、フォームが送信される前に入力エラーをユーザーに通知できる。これはユーザーがエラーを修正する方法について即座にフィードバックを得るため、サーバー側の検証よりも優れたユーザーエクスペリエンスを提供する。
AngularJS のコントロールは、所定の入力、選択またはテキストエリアのプロパティを公開しているので、それを CSSクラスに関連付けます。
- $dirty (CSS クラス ng-dirty):コントロールが相互作用されダーティな状態(何らかの入力がなされている状態)
- $pristine (CSS クラス ng-pristine):コントロールがまだ相互作用していない手付かずの状態
- $valid (CSS クラス ng-valid):モデルが有効
- $invalid (CSS クラス ng-invalid):モデルが無効
注意:本チュートリアルでは、これらのプロパティに焦点を当てます。プロパティとフォームコントロールに関する追加情報は、 AngularJS フォームガイドを参照してください。
AngularJS は、状態に応じて、HTML の入力要素に関するさまざまな CSSクラスを設定します。
AngularJS フォームコントロールの CSS クラスを使用する
注意:「CSSを使用してモーダルウィンドウを作成する方法」のチュートリアルを参照可能です。私たちは、本チュートリアルで先に進む前にそれを読むことをお勧めします。
フィールドの編集直後に入力エラーをユーザーに警告するためには、これらの要素に ng-invalid と ng-dirty クラスを使用する必要があります。
お好みのエディタで以下のクラスを含む validationStyle.css ファイルを作成します:
.ng-invalid.ng-dirty {
border-color: red;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(233,175,102,.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(233,175,102,.6);
}
ng-invalid クラスだけの使用は、ユーザが値を入力する前にその入力フィールドに赤い枠を表示させるので、うっとうしいかも知れません。したがって、ユーザーがフィールドに値を入力したときにその値が有効/無効であることを表示するには、先の CSS ファイルを編集して次の CSS を追加します。そして、フォームの下部にある「ASSETS」パネルで「新規アセットを追加」をクリックし て、この CSS ファイルを追加します。
.ng-valid {
border-color: blue;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 4px rgba(102,233,102,.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 4px rgba(102,233,102,.6);
}
このフォームは、UI デザイナーのプレビューで、次のように表示されます:
注意:フォームコントロールのプロパティは $form 変数にも適用します。
したがって、この場合には、$form 変数は、そのコントロールの各値に応じて $invalid, $valid, $pristine および $dirty のプロパティを持ちます。コントロールの1つが true に設定されたプロパティを持つ場合、プロパティに一致するその$form 変数には、true に設定されています。したがって、HTML のフォーム要素は、$form のプロパティが true か false であるかどうかが設定された関連する $invalid, $valid, $pristine および $dirty クラスを持ちます。
HTML のフォーム要素は境界を持たないため、追加した CSS クラスは、それに影響を与えません。
エラーの要約パネル(サブスクリプション版のみサポート)
デバッグ目的のためには、フォームの一番上にすべてのエラーを一覧表示するパネルを追加することができます。このためには、UI デザイナーのホーム・ページで「フラグメント」を作成します。このフラグメントは errorPanel と命名します。下部の「VARIABLES」パネルで errors と呼ぶ1つの変数を作成し、「公開しますか」のタイプを「はい」に設定します。次の別の2つの変数を作成し「公開しますか」のタイプを「いいえ」に設定します:
- errorRequired:いくつかの必要なデータが不足している場合には、フォーム内でそれを伝えることができます。
- errorDate:いくつかの日付が無効である場合には、フォーム内でそれを伝えることができます。
これらの2つの変数は、$form.$error のコンテンツを参照する JavaScript 式で初期化します。そのためには、「タイプ」で「Javascript expression」を選択し、errorRequired に次の値を入力します:
return ($data.errors.required || []).filter(function(field){
return field.$dirty;
}).map(function(field){
return field.$name;
});
そして、errorDate に次の値を入力します。
return ($data.errors.date || []).map(function(field){
return field.$name;
});
errorRequired は、 errorDate と少し異なります。フォームが空の場合、いくつかのフィールドが空であることをユーザーに気付かせる必要がないため、ダーティフィールド(何らかの編集を行われたフィールドのこと)のエラーだけを表示するようにフィルタに仕組んでいます。
これらの2つの変数は無効なウィジェット名のリストを持っていますが、それらは自動的に生成されるため、現在、これらのウィジェットの名前は直接使用できません。したがって、左側のパレットから2つの TEXT ウィジェットをこのフラグメントホワイトボードにドラッグ&ドロップし、次のテキストを値に設定します。
- いくつかの必要なデータが不足しています。
- いくつかの日付は無効です。
テキストと赤の背景を配置するには、両方のウィジェットのプロパティにブートストラップの text-danger と bg-danger の CSS クラスを追加します。エラーが検出されていない場合、これらのフィールドを非表示にするために、各ウィジェットの「非表示」プロパティに移動し、「fx」をクリックして、それぞれに次の式を追加します:
- !errorRequired || errorRequired.length === 0
- !errorDate || errorDate.length === 0
下図に示すように:
次に、p の htmlタグのデフォルトスタイルを変更し、もう少しマージンに余裕を持たせるため、validationStyle.css のファイルを開いて、次の行を追加します。
.text-danger p {
margin: 1em;
}
UI デザイナーのホームページに戻り、再度休暇申請フォームを開きます。
左側のパレットで「フラグメント」を選択し、作成したフラグメントをフォーム タイトルの下にドラッグ&ドロップします。そのフラグメントの「errors」プロパティに「$form.$error」をバインドします。
プレビューでテストすると下図のようの表示されます。
休暇の種類に SELECT ウィジェットを使用する
ユーザーは通常、休暇タイプの一つの選択肢を選択し、自由にテキストを入力していません。このような値の定義済みリストは次のようになります。
- 年次休暇
- リフレッシュ休暇
- その他
このようなリストを実装するためには、生成された INPUT ウィジェットを削除し、次のプロパティを持つ SELECT ウィジェットを追加します:
- ラベル:種類
- 必須:はい
- プレース ホルダー:休暇の種類
- 使用可能な値:年次休暇, リフレッシュ休暇, その他
- 値:formInput.leaveRequest.type
検証のカスタマイズ
サーバー側からのコントラクト検証応答メッセージを使用する
これまでの段階では、あなたは、種々の入力にいくつかの簡単なコントロールを追加しました。これからは、より高度な入力エラーチェック方法を学習します。たとえば、次の3つのルールを表現してみましょう:
- 開始日は終了日よりも早いか同じでなければならない
- 日数はゼロより大きくなければならない
- 休暇の種類は、年次休暇, リフレッシュ休暇, その他のいずれか1つでなければならない
第二の要件については、既に入力上のコントロールを設定しています。最後の要件については、既にタイプを INPUT ウィジェットから SELECT ウィジェットに変更しています。
したがって、これらの2つのフィールドに対し、ユーザーが間違ったデータを送信することはありません。
しかし、クライアント側の検証は、優れたユーザーエクスペリエンスを提供する上で重要な役割を果たしている一方で、それは簡単に回避することができるため、信頼できないことに注意してください。サーバー側での検証は、セキュアなアプリケーションのために依然として必要です。
このような理由から、私たちはプロセス側のコントラクト内でこれらのルールを制約として追加する必要があります。
Studio に戻って、プールレベルの「実行」ペイン> 「コントラクト」 > 「制約」タブに移動し、次の制約を定義します:
フォームを送信したときに制約の1つが false になった場合、サーバーのエラー応答メッセージは、explanations (説明)属性を持ちます。
この属性は、false になった各制約のエラーメッセージの配列です。
UI デザイナー側では、送信時のエラー応答メッセージをキャッチする必要があります。そうするには、フォームの「VARIABLES」パネルに移動し、instantiationErrorResponse と呼ぶ新しい変数を作成します。そして、「Submit」ボタンを選択し、「失敗時のレスポンス値」のプロパティにその instantiationErrorResponse を入力します。
次に、各エラーメッセージを赤でフォーム上に表示する必要があるので、説明メッセージの反復を作成します。パレットから「CONTAINER」をフォームタイトルの直下にドラッグ&ドロップし、そのコンテナの「コレクション」プロパティに instantiationErrorResponse.explanations を入力します。
このコンテナの内部に、TEXT ウィジェットを追加し、その 「CSS クラス」のプロパティに text-danger と bg-danger を入力し、「Text」のプロパティに {{$item}} を入力します 。
次に、Studio に戻ってフォーム送信時のエラーメッセージをテストするため、プロセスを実行します(UI デザイナーでプレビューしても送信時のエラー検証は行われません)。
終了日より古い開始日を設定した場合に、次の画面が生成されます(他のフィールドは正しく設定されている前提):
フロントエンドの検証を使用する
休暇申請フォームにさらに2つの制約を追加してみましょう:
- nbDays は 0より大きく、外部から取得された値(たとえば、社員の年次休暇残日数)より小さくなければならない
- type の値が「その他」の場合は、100文字以内に制限した「コメント」フィールドを表示する(人事担当者はその休暇が何のためか知る必要があるため)
数値入力値のコントロール
ユーザーがフォームに必要事項を記入する際、その社員の休暇残日数にしたがって入力した取得休暇日数が有効であるか伝えるために、新しい変数 remainDays を作成します。この変数の値は、年次休暇のために残された日数を提供します。
この変数のタイプは実際には、外部から値を取得する External API でなければなりませんが、このチュートリアルではフォームをテストするために、とりあえず Javascript expression のタイプにして、 次の JavaScript 式を設定します。
var testData={
"リフレッシュ休暇": 2,
"年次休暇": 12
};
return testData[$data.formInput.leaveRequest.type];
次に、取得休暇日数のINPUT ウィジェットで、「最小値」のプロパティを 0.5 に設定し、「最大値」のプロパティに変数 remaingDays を設定します。
これを行うと、休暇の種類に応じた日数の値を検証することができます。
フォームにより自然な流れ与えるため(休暇の種類の選択を取得休暇日数の前に)入力順序を変更します。
取得休暇日数の INPUT ウィジェットのフォームコントロールは先の設定によって、入力検証のために2つの新しい CSS クラス(ng-invalid-minとng-invalid-max)を公開します。同様に、$error はそれぞれが最小値以下または最大値以上である場合、その最小値と最大値の属性を保持します。
あなたがフォームの休暇の種類をリフレッシ休暇に設定した後に、取得休暇日数を間違って入力した場合、次のようになります。
テキスト入力値のコントロール
さて、Studio のビジネス データモデルのビジネス・オブジェクト LeaveRequest に、入力コントラクトの comment に対応する新しい comment 属性が追加されていることを前提とします。このコメントは、休暇の種類が「その他」である場合、記入されていなければなりません。
このコメントを表示するには、種類のウィジェットの右側に TEXT AREA ウィジェットを追加します。
休暇の種類が「その他」に選択された場合にのみ、このウィジェットを表示するさせるためには、このテキストエリアの「非表示」プロパティを「はい」にし、式に変更(「fx」をクリック )して、「formInput.leaveRequest.type !== ‘その他’」を設定します。
それが表示される場合はそれを入力必須にするには、「必須」プロパティの「はい」にし、式に変更して、「formInput.leaveRequest.type === ‘その他’ 」を設定します。
下図に示すように「ラベル」のプロパティに「コメント」を入力し、「値」プロパティに「formInput.leaveRequest.comment」をタイプします:
テキストが妥当なサイズになるようにユーザに入力を強制するには、「値の最小文字数」を 5 に、「値の最大文字数」を 100 に設定し、このウィジェットのフォームコントロールを追加します。
コメントの TEXT AREA ウィジェットのフォームコントロールは先の設定によって、入力検証のために2つの新しい CSS クラス(ng-invalid-minlength と ng-invalid-maxlength)を公開します。同様に、$error はそれぞれが文字数の最小長を下回るか、最大長を超えている場合、その最小長と最大長の属性を保持します。
UI デザイナーのプレビューで「種類」を「その他」に選択し、表示された「コメント」に短いコメントを入力すると、次のような結果になります。