この章では、ADF Facesコンポーネントを使用した、データ・コントロール・パレットでのデータ・バインド・フォームの作成方法を説明します。
この章の内容は次のとおりです。
ビジネス・サービス用に作成されたデータ・コントロールを使用して情報の表示および収集を行うための、UIウィジェットを作成できます。たとえば、データ・コントロール・パレットを使用して、項目の属性をドラッグし、読取り専用テキストまたはラベル付き入力テキスト・フィールドとして、値を表示できます。
JDeveloperでは、属性を個別にドロップする必要はなく、オブジェクトのすべての属性をフォームとして一度にドロップできます。フォームを構成する実際のUIコンポーネントは、ドロップしたフォームのタイプによって異なります。値を表示するフォーム、ユーザーが値を編集できるフォーム、値を収集するフォーム(入力フォーム)および検索フォームを作成できます。
UIコンポーネントをドロップしたら、ユーザーがデータを操作できるようにするための組込み操作を、コマンドUIコンポーネントとしてドロップできます。たとえば、フォームに表示されたデータ・オブジェクト間をユーザーが移動できるようにするためのボタンを作成できます。また、必要に応じてデフォルトのコンポーネントを変更することもできます。
この章の内容は次のとおりです。
個々のデータ・バインド・テキスト・フィールドの作成方法
複数のテキスト・フィールドで構成されるフォームの作成方法
既存オブジェクトの編集または新規オブジェクトの作成が可能なフォームなど、様々なタイプのフォームの作成方法
フォームに表示されるデータ・オブジェクト間を移動するための操作、またはデータ操作を可能にする操作の追加方法
作成済フォームの変更方法
テキスト・フィールドを作成するには、属性バインディングを使用して、ADF FacesテキストUIコンポーネントをデータ・コントロールの属性にバインドします。JDeveloperでは、この処理をコードを記述せずに宣言的に行うことができます。また、JDeveloperには、JSFページ用の完全なWYSIWYG開発環境が用意されているため、ページのほとんどの内容をコードを見ずに設計することができます。
属性の表示または更新を行えるテキスト・フィールドを作成するには、データ・コントロールを使用して、UIコンポーネントを属性にバインドする必要があります。JDeveloperでは、データ・コントロール・パレットからコレクションの属性をドラッグ・アンド・ドロップして、この処理を宣言的に行えます。
バインドされたテキスト・フィールドの作成手順:
データ・コントロール・パレットからコレクションの属性を選択します(属性およびデータ・コントロール・パレットのその他のオブジェクトを表すアイコンの説明は、12.2.1項「データ・コントロール・パレットの各項目の理解」を参照してください)。
たとえば、図13-1は、SRDemoアプリケーションのSRService
データ・コントロールの、ServiceRequests
コレクションの下にあるProblemDescription
属性を示しています。この属性は、サービス・リクエストに対する問題の説明を表示または入力する場合にドロップします。
ページに属性をドラッグし、ポップアップ・メニューから、属性値を表示または収集するウィジェットのタイプを選択します。各属性について、次の選択肢があります。
テキスト
ラベル付ADF出力テキスト: ADF Faces outputText
コンポーネントを保持するpanelLabelAndMessage
コンポーネントを作成します。panelLabelAndMessageコンポーネントのlabel
属性に値が移入されます。
ADF出力テキスト: ADF Faces outputText
コンポーネントを作成します。ラベルは作成されません。
ラベル付ADF入力テキスト: validator
を伴うADF Faces inputText
コンポーネントが作成されます。label
属性に値が移入されます。
ADF入力テキスト: validator
を伴うADF Faces inputText
コンポーネントが作成されます。label
属性に値は移入されません。
ADFラベル: ADF Faces outputLabel
コンポーネント。
単一選択
これらのウィジェットによって、リストが表示されます。この章の目的にあわせて、ここではテキスト・ウィジェットのみについて説明します。リストおよびそのバインディングの詳細は、19.7項「選択リストの作成」を参照してください。
JSFページに属性をドラッグしてUIコンポーネントとしてドロップすると、ページのディレクトリ名を含むJSFページの名前を使用し、ページ定義ファイルの名前としてJSFページの名前にPageDef
を追加して、そのページのページ定義ファイル(すでに存在する場合を除く)などが作成されます。たとえば、Webルートの./app/staffサブディレクトリのSREditページのページ定義ファイルは、app_staff_SREditPageDef.xml
です。属性をページにドラッグしたときに行われる処理の詳細は、12.2.3項「データ・コントロール・パレットの使用時に行われる処理」を参照してください。イテレータと属性のバインディングが作成され、ページ定義ファイルに追加されます。また、UIコンポーネントに必要なJSPXページのコードがJSFページに追加されます。
データ・コントロール・パレットからコレクションの一部である項目をドロップして(またはコレクション全体をフォームまたは表としてドロップして)ページ上にUIコンポーネントを作成するたびに、既存のバインディングが存在しない場合はJDeveloperでイテレータ・バインディングが作成されます。イテレータ・バインディングは、データ・コレクションのイテレータを参照し、この機能によりそのデータ・オブジェクトを反復処理します。また、コレクション内のデータ・オブジェクトの現在行および状態を管理します。イテレータ・バインディングは実際にはデータにアクセスしません。かわりに、データにアクセスできるオブジェクトを単純に公開し、コレクション内の現在のデータ・オブジェクトを指定します。その後、現在のオブジェクトのデータを戻したり、オブジェクトのデータに対してアクションを実行するために、他のバインディングがこのイテレータ・バインディングを参照します。イテレータ・バインディングはイテレータではなく、イテレータへのバインディングであることに注意してください。ADF Business Componentsの場合、実際のイテレータは、アプリケーション・モジュールのデータ・モデル内のビュー・オブジェクト・インスタンスのデフォルト行セットに対するデフォルト行セット・イテレータです。
ヒント: 各コレクションに対して1つのイテレータ・バインディングが作成されます。つまり、同じコレクションから2つの属性をドロップした場合(もしくは同じコレクションを2回ドロップした場合)は、同じバインディングが使用されます。コンポーネントごとに動作の異なるバインディングが必要な場合を除き、同じバインディングが使用されても問題はありません。その場合は、別個のイテレータ・バインディングを手動で作成する必要があります。手順と例は、18.5項「検索ページの結果表の条件付き表示」を参照してください。 |
たとえば、ServiceRequests
コレクションの下にProblemDescription
属性をドロップした場合、ServiceRequests
コレクションのイテレータ・バインディングが自動的に作成されます。
イテレータ・バインディングのrangeSize
属性は、イテレータ・バインディングへのアクセスが行われるたびにページに対して使用可能なレコードの数を決定します。この属性により、行セット全体の中でいくつかの絶対開始位置に対して1-N行の相対セットが置かれます。デフォルトでは10
に設定されています。この属性の使用方法は、13.4.2.2項「イテレータのRangeSize属性」を参照してください。例13-1に、ServiceRequests
コレクションから属性をドロップすると作成されるイテレータ・バインディングを示します。
例13-1 コレクションから属性をドロップした場合のイテレータ・バインディングのページ定義コード
<executables> <iterator id="ServiceRequestsIterator" RangeSize="10" Binds="ServiceRequests" DataControl="SRService"/> </executables>
イテレータ・バインディング要素の属性に関する詳細は、A.2.2項「Oracle ADFデータ・バインディング・ファイル」を参照してください。
このメタデータにより、ADFバインディング・コンテナは属性にアクセスできます。イテレータ・バインディングは実行可能ファイルで、ページのロード時に起動されるため、これによってイテレータがServiceRequests
コレクションにアクセスし、反復処理を行うことができます。これは、コレクションのサービス・リクエストがすべてこのイテレータによって管理されることを意味します。現在のサービス・リクエストやサービス・リクエストのレンジの判別も含まれます。
データ・コントロール・パレットから属性をドロップすると、JDeveloperによって、UIコンポーネントを属性の値にバインドするための属性バインディングが作成されます。このタイプのバインディングは、コレクション内の現在行のシングル・オブジェクトに対する属性の値を提示します。値バインディングは、属性値の表示と収集の両方に使用できます。
たとえば、ServiceRequests
コレクションの下にあるProblemDescription
属性を「ラベル付ADF出力テキスト」ウィジェットとしてページにドロップすると、JDeveloperによって、ProblemDescription
属性の属性バインディングが作成されます。これにより、バインディングが現在のレコードの属性値にアクセスできるようになります。例13-2に、ServiceRequests
コレクションから属性をドロップすると作成されるProblemDescription
に対する属性バインディングを示します。この属性値は、ServiceRequests
Iterator
という名前のイテレータを参照します。
例13-2 属性バインディングのページ定義コード
<bindings> ... <attributeValues id="ServiceRequestsProblemDescription" IterBinding="ServiceRequestsIterator"> <AttrNames> <Item Value="ProblemDescription"/> </AttrNames> </attributeValues> </bindings>
属性バインディング要素の属性に関する詳細は、A.2.2項「Oracle ADFデータ・バインディング・ファイル」を参照してください。
データ・コントロール・パレットから属性をドロップしてテキスト・フィールドを作成すると、JDeveloperによって、対応するコードがJSFページに記述され、ドロップしたウィジェットに関連付けられているUIコンポーネントが作成されます。
たとえば、ProblemDescription
属性を「ラベル付き出力テキスト」ウィジェットとしてドロップすると、JDeveloperによって、panelLabelAndMessage
label
の属性をProblemDescription
バインディングのlabel
プロパティにバインドするEL式が作成されます。また、panelLabelAndMessage
値属性をProblemDescription
バインディングのinputValue
プロパティ(ProblemDescription
属性の値)にバインドする、別の式が作成されます。バインディング・オブジェクト・プロパティに関する詳細は、A.2.2項「Oracle ADFデータ・バインディング・ファイル」を参照してください。
例13-3は、ProblemDescription
属性を「ラベル付き出力テキスト」ウィジェットとしてドロップしたときに、JSFページで生成されるコードを示しています。
例13-3 「ラベル付き出力テキスト」としてドロップされた属性のJSFページ・コード
<af:panelLabelAndMessage label="#{bindings.ServiceRequestsProblemDescription.label}"> <af:outputText value="#{bindings.ServiceRequestsProblemDescription.inputValue}"/> </af:panelLabelAndMessage>
かわりにProblemDescription
属性をラベル付き入力テキスト・ウィジェットとしてドロップすると、JDeveloperによってinputText
コンポーネントが作成されます。例13-4で示すように、出力テキスト・コンポーネントと同様に、値はProblemDescription
バインディングのinputValue
プロパティにバインドされます。また、次のプロパティも設定されます。
label
: バインディングのlabel
プロパティにバインドされます。
required
: バインディングのmandatory
プロパティにバインドされます。このプロパティの詳細は、20.3項「検証の追加」を参照してください。
columns
: displayWidth
プロパティにバインドされます。テキスト・ボックスの幅を決定します。
例13-4 ラベル付き入力テキストとしてドロップされた属性のJSFページ・コード
<af:inputText value="#{bindings.ServiceRequestsProblemDescription.inputValue}" label="#{bindings.ServiceRequestsProblemDescription.label}" required="#{bindings.ServiceRequestsProblemDescription.mandatory}" columns="#{bindings.ServiceRequestsProblemDescription.displayWidth}"> <af:validator binding="#{bindings.ServiceRequestsProblemDescription.validator}"/> </af:inputText>
プロパティの詳細は、付録B「ADFバインディング・プロパティのリファレンス」を参照してください。
ページが送信され、新しいページがリクエストされると、アプリケーションによってJSFライフサイクルとADFライフサイクルの両方が起動されます。JSFライフサイクルは、ビュー・レイヤーでコンポーネントを処理しますが、ADFライフサイクルは、モデル・レイヤーでデータを処理します。
特に、JSFファイルサイクルは、ページ上での値の送信、作成されるページでのコンポーネントの検証、ナビゲーションおよびコンポーネントの表示、そして保存およびリストアの状態を処理します。JSFライフサイクルのフェーズでは、UIコンポーネント・ツリーを使用して、Facesコンポーネントの表示が管理されます。このツリーは、JSFページの実行時の表現であり、ページ内のUIコンポーネントのタグは、それぞれツリー内の1つのUIコンポーネント・インスタンスに対応します。FacesServlet
オブジェクトは、JSFアプリケーションでのリクエスト処理のライフサイクルを管理します。FacesServlet
は、FacesContext
というオブジェクトを作成します。このオブジェクトには、リクエスト処理およびライフサイクルを実行するオブジェクトの起動に必要な情報が含まれます。
ADFライフサイクルは、データ・モデルの準備と更新、モデル・レイヤーでのデータの検証、およびビジネス・レイヤーでのメソッドの実行を処理します。ADFライフサイクルは、バインディング・コンテナを使用して、現在ページのリクエスト時にページによる簡単なデータ参照を可能にします。
ライフサイクルは複数のフェーズに分かれます。2つのライフサイクルが連携して動作するように、JSFイベント・リスナーのメカニズムを使用して、ADFライフサイクルのフェーズがJSFライフサイクルのフェーズに統合されます。ADFライフサイクルは、ADFフェーズ・リスナーを使用して、フェーズのイベントをリスニングします。これにより、適切なJSFフェーズの前または後に、適切なADFフェーズが実行されます。
ADFデータ・コントロールにバインドされたADF Facesコンポーネントが最初にJSFページに挿入された際には、JDeveloperによって、ADF PhaseListenerがfaces-config.xml
に追加されます。例13-5は、faces-config.xml
でのADF PhaseListenerの構成を示しています。
例13-5 faces-config.xmlでのADF PhaseListenerの登録
<faces-config xmlns="http://java.sun.com/JSF/Configuration"> ... <lifecycle> <phase-listener> oracle.adf.controller.faces.lifecycle.ADFPhaseListener </phase-listener> </lifecycle> ... </faces-config>
図13-2は、JSFおよびADFのフェーズがライフサイクルの中でどのように統合されるかを示しています。
ADFモデル・レイヤーを使用するJSFアプリケーションでは、ライフサイクルは次のようになります。
ビューのリストア: リクエストされたページのURLがbindingContext
に渡され、URLと一致するページ定義が検索されます。リクエストされたページのコンポーネント・ツリーが、新しく作成されるかリストアされます。送信されたページ上のすべてのコンポーネント・タグ、イベント・ハンドラ、コンバータおよびバリデータは、FacesContext
インスタンスにアクセスできます。ツリーが新しく、空の場合(つまり、送信されたページからのデータがない)は、ライフサイクルは直接レスポンスのレンダリング・フェーズに進みます。それ以外の場合は、ビューのリストア・フェーズによって、ADFモデル・レイヤーのコンテキストの初期化フェーズがリスニングするイベントが発行され、実行されます。
たとえば、ページに含まれているinputText
UIコンポーネントがServiceRequest
戻りコレクションのProblemDescription
属性にバインドされている場合、URLが渡されると、そのページ定義が公開されます。その後、UIコンポーネントが作成されます。データが表示される場合は、コンテキストの初期化フェーズが実行されます。表示されない場合は、ライフサイクルがレスポンスのレンダリング・フェーズに進みます。
コンテキストの初期化: ページ定義ファイルを使用してbindingContainer
オブジェクトが作成されます。このオブジェクトは、リクエストされたページのページ定義の実行時表現です。ADFライフサイクルの全フェーズの情報を保存するために使用されるLifecycleContext
クラスがインスタンス化され、初期化されます。
モデルの準備: バインディング・コンテナがリフレッシュされ、ページ定義に含まれるすべてのページ・パラメータが設定されます。Refresh
属性およびRefreshCondition
属性の値に基づいて、ページ定義の実行可能セクションに含まれるすべてのエントリがリフレッシュされます。
Refresh
およびRefreshCondition
属性は、実行可能セクションを起動するかどうか、またいつ起動するかを決定するために使用されます。たとえば、実行可能セクションが、ある一定の条件下でのみ起動する必要があるという場合です。リフレッシュは、実行可能セクションを起動するフェーズを決定します。一方で、リフレッシュ条件は条件が満たされているかどうかを判断します。バインディングが操作の結果に依存する場合は、Refresh
属性をprepareModel
に設定します。Refresh
がprepareModel
に設定されているか、値が指定されていない(つまり、デフォルトのifneeded
が使用される)場合は、RefreshCondition
属性値が評価されます。RefreshCondition
値が存在しない場合は、実行可能セクションが起動します。RefreshCondition
の値が存在する場合は、値が評価され、評価の戻り値がtrueの場合は、実行可能セクションが起動します。値がfalseと評価された場合は、実行可能セクションは起動しません。デフォルト値は常に、実行を強制します。受け取ったリクエストにPOSTデータまたは問合せパラメータが含まれていない場合、ライフサイクルはレスポンスのレンダリング・フェーズに進みます。
詳細は、10.5.5.1項「イテレータ・バインディングのRefreshプロパティの適切な構成」を参照してください。リフレッシュ属性の詳細は、A.6.1項「PageDef.xmlの構文」を参照してください。
問題の説明の例では、bindingContainer
によって、ServiceRequests
コレクションを戻すServiceRequestsIterator
イテレータが起動されます。その後、イテレータによってデータが反復処理され、最初に検出されたレコードのデータがバインディング・コンテナに配置されて、UIコンポーネントで使用できるようになります。イテレータからの値にアクセスできるページ定義内のProblemDescription
属性にバインディングが設定されているため(例13-2を参照)、また、EL式(#{bindings.problemDescription.inputValue}
)を使用してUIコンポーネントがProblemDescription
バインディングにバインドされているため、そのデータがコンポーネントによって表示されます。
リクエスト値の適用: ツリー内の各コンポーネントにより、リクエスト・パラメータから(そのデコード・メソッドを使用して)新しい値が抽出され、ローカルに格納されます。関連付けられているほとんどのイベントは、後の処理のためにキューされます。コンポーネントのimmediate
属性がtrue
に設定されている場合は、コンポーネントに関連付けられている検証、変換およびイベントが、このフェーズで処理されます。検証および変換の詳細は、第20章「検証と変換の使用」を参照してください。
たとえば、ユーザーがinputText
コンポーネントに新しい値を入力すると、その値はinputText
コンポーネントのsetSubmittedValue
メソッドを使用してローカルに格納されます。
処理の検証: コンポーネントのローカルの値が変換され、検証されます。エラーが発生した場合は、ライフサイクルがレスポンスのレンダリング・フェーズに進みます。このフェーズの最後に、コンポーネントの新しい値が設定され、検証または変換のエラー・メッセージおよびイベントがFacesContext
でキューされて、すべての値変更イベントが配信されます。
ライフサイクルのこのフェーズおよび後続の2つのフェーズの詳細な説明は、第20章「検証と変換の使用」を参照してください。
アプリケーションの起動: コマンド・コンポーネントまたはイベントのアクション・バインディングが起動されます。ライフサイクルのこのフェーズおよび後続の2つのフェーズの詳細な説明は、16.4項「動的ナビゲーションの使用」を参照してください。ビジネス・ロジックの起動に使用されるアクション・バインディングの説明は、13.4項「フォームへのレンジ・ナビゲーションの組込み」を参照してください。
メタデータのコミット: 実行時メタデータへの変更がコミットされます。このフェーズは今回のリリースでは使用されていませんが、将来のリリースで使用されます。
コンテキストの初期化(アプリケーションの起動ライフサイクルでナビゲーションが発生した場合のみ): 次のページのページ定義が初期化されます。
モデルの準備(アプリケーションの起動ライフサイクルでナビゲーションが発生した場合のみ): 次のページの定義に含まれるすべてのページ・パラメータが設定されます。ページ定義の実行可能セクションに含まれるすべてのエントリを使用して、対応するメソッドが表示順に起動されます。
レンダリングの準備: バインディング・コンテナがリフレッシュされ、リクエスト値の適用フェーズまたは検証フェーズで発生したすべての変更が反映されます。登録されたすべてのリスナーに、prepareRender
イベントが送信されます。
注意: 選択する有効フェーズとして、JDeveloperではprepareRender ではなくrenderModel が表示されます。これは、バインディング・コンテナでコールされるrefresh(RENDER_MODEL) メソッドを表します。 |
refreshCondition
がモデルに依存する場合は、実行可能セクションのRefresh
属性をrenderModel
に設定する必要があります。たとえば、実行可能セクションのRefreshCondition
で#{adfFacesContext.postback}
式を使用する場合は、Refresh
プロパティをrenderModel
またはrenderModelIfNeeded
に設定する必要があります。これにより、メソッドがprepareRender
フェーズ中に実行されます。詳細は、10.5.5.1項「イテレータ・バインディングのRefreshプロパティの適切な構成」を参照してください。
レスポンスのレンダリング: J2EE Webコンテナがページ内のタグを横断するにつれて、ツリー内のコンポーネントがレンダリングされます。後続のリクエストおよびビューのリストア・フェーズ用に、状態の情報が保存されます。
JDeveloperでは、属性を個別にドロップしてフォームを作成するのではなく、オブジェクトのすべての属性のデータを表示または収集する、完全なフォームをドロップできます。たとえば、SREditページは、指定されたサービス・リクエストの編集に必要なすべての属性が含まれているServiceRequests
コレクションをドロップして作成されています。
コレクションからのデータ表示よりも多くの機能を提供するフォームの作成もできます。ユーザーによるデータ更新が可能なフォームの作成については、13.5項「既存レコードを編集するフォームの作成」を参照してください。ユーザーによるコレクションに対する新規オブジェクト作成が可能なフォームの作成については、13.6項「入力フォームの作成」を参照してください。また、検索フォームも作成できます。詳細は、第18章「検索フォームの作成」を参照してください。
データ・コントロールを使用してフォームを作成するには、UIコンポーネントをデータ・コントロールの対応するオブジェクトの属性にバインドします。JDeveloperでは、データ・コントロール・パレットからコレクションまたは構造化された属性をドラッグ・アンド・ドロップして、この処理を宣言的に行えます。
基本的なフォームの作成手順:
データ・コントロール・パレットから、表示するデータを表すコレクションを選択します。図13-3に、SRService
データ・コントロールのServiceRequests
コレクションを示します。
ページにコレクションをドラッグし、ポップアップ・メニューから、オブジェクトのデータを表示または収集するフォームのタイプを選択します。各フォームについて、次の選択肢があります。
ADFフォーム: 「フォーム・フィールドの編集」ダイアログが開き、デフォルトですべての属性に対して1つのフィールドを作成するのではなく、属性を個別に選択できます。また、各属性に使用するラベルおよびUIコンポーネントを選択できます。デフォルトでは、ADF inputText
コンポーネントが使用されますが、例外として、日付にはselectInputDate
コンポーネントが使用されます。各inputText
コンポーネントには、属性の検証を設定するためのバリデータ・タグが含まれます。詳細は、20.3項「検証の追加」を参照してください。
ユーザーがコレクション内の全データ・オブジェクト間を移動できるようにする、ナビゲーション・コントロールを含めることもできます。詳細は、13.4項「フォームへのレンジ・ナビゲーションの組込み」を参照してください。必要に応じて、フォームを送信するための「発行」ボタンを含めることもできます。このボタンにより、HTMLフォームを送信し、JSF/ADFページ・ライフサイクルの一環としてフォームのデータをバンディングに適用します。このダイアログの使用方法に関する追加のヘルプを表示するには、「ヘルプ」をクリックします。すべてのUIコンポーネントは、panelForm
コンポーネントの中に配置されます。
ADF読取り専用フォーム: 「ADFフォーム」と同じですが、デフォルトではoutputText
コンポーネントが使用されます。このフォームはデータの表示を目的としているため、validator
タグは追加されません。各コンポーネントのlabel
属性に値が移入されます。タイプDate
の属性でも、outputText
コンポーネントが使用されます。すべてのコンポーネントはpanelLabelAndMessage
コンポーネントの中に配置され、panelLabelAndMessage
コンポーネントはpanelForm
コンポーネントの中に配置されます。
ADF検索フォーム: Query-By-Example(QBE)検索の実行に使用できるフォームを作成します。詳細は、第18章「検索フォームの作成」を参照してください。
ADF作成フォーム: ユーザーがコレクションの新規インスタンスを作成できる入力フォームを作成します。詳細は、13.6項「入力フォームの作成」を参照してください。
ユーザーがデータを更新できるようにするためのフォームを作成する場合は、ここで、更新を実行する操作をドラッグ・アンド・ドロップする必要があります。詳細は、13.5項「既存レコードを編集するフォームの作成」を参照してください。
データ・コントロール・パレットからオブジェクトをフォームとしてドロップすることは、単一の属性をドロップするのと同じ効果があります。ただし、複数の属性バインディングと関連するUIコンポーネントが作成される点が異なります。UIコンポーネントの属性(value
など)は、その属性のバインディング・オブジェクト(inputValue
など)のプロパティにバインドされます。例13-6は、ServiceRequests
コレクションをデフォルトADFフォームとしてドロップした場合にJSFページで生成されるコードを示しています。
例13-6 入力フォームのJSFページのコード
<af:panelForm> <af:inputText value="#{bindings.SvrId.inputValue}" label="#{bindings.SvrId.label}" required="#{bindings.SvrId.mandatory}" columns="#{bindings.SvrId.displayWidth}"> <af:validator binding="#{bindings.SvrId.validator}"/> </af:inputText> <af:inputText value="#{bindings.Status.inputValue}" label="#{bindings.Status.label}" required="#{bindings.Status.mandatory}" columns="#{bindings.Status.displayWidth}"> <af:validator binding="#{bindings.Status.validator}"/> </af:inputText> <af:selectInputDate value="#{bindings.RequestDate.inputValue}" label="#{bindings.RequestDate.label}" required="#{bindings.RequestDate.mandatory}"> <af:validator binding="#{bindings.RequestDate.validator}"/> <f:convertDateTime pattern="#{bindings.RequestDate.format}"/> </af:selectInputDate> ... </af:panelForm>
JSFコンポーネントでは、ファセット・タグを使用して、親コンポーネントとの特別な関係が要求される他のコンポーネント(たとえば、表の列のヘッダーとフッター、またはpanelForm
コンポーネントのfooter
)が保持されます。データ・コントロール・パレットを使用してウィジェットをドロップすると、デフォルトのファセットが組み込まれます。
ファセットは多くのコンポーネントで使用されます。ウィジェットを使用して複雑なコンポーネント(panelForm
など)を作成する際には、多くの場合、出力タグが自動的に作成され、ファセットに挿入されます。これらのコンポーネントを手動で編集するか、他のコンポーネントをファセットに追加できます。
コレクションを入力フォームとしてドロップする際に「発行」ボタンを含めることを選択した場合は、コマンド・ボタンがpanelForm
のfooter
ファセットに追加されます。このコマンド・ボタンによって、panelForm
を保持するフォームが送信されます。デフォルトでは、テキストは「発行」になります。図13-4は、panelForm
のfooter
ファセットのコマンド・ボタンを示しています。
例13-7は、JSFページの対応するコードを示しています。
例13-7 JSFページのファセット
<af:panelForm> ... <f:facet name="footer"> <af:commandButton text="Submit"/> </f:facet> </af:panelForm>
各ファセットで保持できるのは1つのコンポーネントのみです。複数のコンポーネントを保持するファセットが必要な場合は、複数のコンポーネントを1つのコンテナ・コンポーネントにネストし、ファセットにネストできる状態にする必要があります。たとえば、panelGroup
コンポーネントとpanelButtonBar
コンポーネントは、フォームのfooter
ファセットにあるすべてのボタンのグループ化に使用されています。これに関する詳細は、13.4.2.3項「EL式を使用したナビゲーション操作へのバインド」を参照してください。
また、コンポーネントに使用できるすべてのファセットは、構造ウィンドウに自動的に表示されます。ただし、アクティブな状態で表示されるのは、UIコンポーネントを含むファセットのみです。空のファセットはグレー表示されます。図13-5は、panelPage
コンポーネントの完全なファセットと空のファセットの両方を示しています。
ADFフォームを作成する際、ナビゲーションの追加オプションが提供されます。ナビゲーションの追加を選択する場合、JDeveloperによって、データ・コントロールの既存ナビゲーション・ロジックにバインドされているADF Facesコマンド・コンポーネントが組み込まれます。この組込みロジックによって、ユーザーは、コレクション内のすべてのデータ・オブジェクトを移動できるようになります。図13-6は、ナビゲーション・ボタンを含むフォームを示しています。
デフォルトでは、データ・コントロール・パレットを使用してフォームを作成する際にナビゲーションを含めることを選択すると、JDeveloperによって、「先頭へ」、「最後へ」、「前へ」および「次へ」の各ボタンが作成され、ユーザーがコレクション内を移動できるようになります。
また、既存のフォームにナビゲーション・ボタンを手動で追加できます。
ナビゲーション・ボタンを手動で追加する場合の手順:
操作の実行対象となるオブジェクトのコレクションに関連付けられている操作をデータ・コントロール・パレットから選択し、JSFページ上にドラッグします。
たとえば、サービス・リクエスト全体を移動できるようにする場合は、ServiceRequests
コレクションに関連付けられている「次へ」操作をドラッグします。図13-7は、コレクションに関連付けられている操作を示しています。
ポップアップ・メニューから「コマンド・ボタン」または「コマンド・リンク」を選択します。
任意の操作をコマンド・コンポーネントとしてドロップすると、JDeveloperによって次の処理が行われます。
関連付けられている操作について、ページ定義ファイルでアクション・バインディングが定義されます。
コマンド・コンポーネント用のコードがJSFページに挿入されます。
アクション・バインディングは、ビジネス・ロジックを実行します。たとえば、アクション・バインディング・オブジェクト上で組込みメソッドを起動できます。このような組込みメソッドは、イテレータやデータ・コントロール自体に対して作用し、データ・コントロール・パレットに操作として表示されます。ユーザーは、JDeveloperによって提供されるナビゲーション操作を使用して、コレクション内の前後のオブジェクトに移動したり、最後または最初のオブジェクトに移動できます。
値バインディングのように、操作のアクション・バインディングには、Next
またはPrevious
などのイテレータレベル・アクションの1つにアクション・バインディングがバインドされる際のイテレータ・バインディングへの参照が含まれます。この参照は、現在のオブジェクトの判別に使用され、これによって、各ナビゲーション・ボタンがクリックされたときに表示するオブジェクトが正しく判別されます(たとえば、AM上のカスタム・メソッドに対して、またはコミット操作やロールバック操作に対して、イテレータレベル・アクション以外にバインドされるアクション・バインディングは、この参照には含まれません)。例13-8は、ナビゲーション操作のアクション・バインディングを示しています。
ヒント: <action> タグのAction 属性の数値(図13-7に示される)は、oracle.adf.model.meta.OperationDefinition クラスで定義されます。ただし、ADFモデル・レイヤーのアクション・バインディング・エディタを使用する場合は、手動で数値コードを設定する必要はありません。 |
例13-8 操作アクション・バインディングのページ定義コード
<action id="First" RequiresUpdateModel="true" Action="12" IterBinding="ServiceRequestsIterator"/> <action id="Previous" RequiresUpdateModel="true" Action="11" IterBinding="ServiceRequestsIterator"/> <action id="Next" RequiresUpdateModel="true" Action="10" IterBinding="ServiceRequestsIterator"/> <action id="Last" RequiresUpdateModel="true" Action="13" IterBinding="ServiceRequestsIterator"/>
イテレータ・バインディングにはrangeSize
属性が含まれ、各イテレータに対してページを使用可能にするデータ・オブジェクト数が決定されます。この属性は、データソース内のオブジェクト数がきわめて多い場合に役立ちます。すべてのオブジェクトではなく、1つのセット番号のみが戻され、他のバインディングによるアクセスが可能になります。イテレータはレンジの最後に到達すると、次のセットにアクセスします。例13-9は、ServiceRequestsIterator
イテレータのデフォルトのレンジ・サイズを示しています。
例13-9 イテレータのRangeSize属性
<executables> <iterator id="ServiceRequestsIterator" RangeSize="10" Binds="ServiceRequests" DataControl="SRService"/> </executables>
デフォルトでは、rangeSize
属性は10
に設定されています。つまり、ユーザーは、データソースにアクセスせずに、前後に移動しながら10個のオブジェクトを表示できます。イテレータは、現在のオブジェクトを追跡します。ユーザーが新しいレンジが要求されるボタンをクリックすると(たとえば、オブジェクト番号10で「次へ」ボタンをクリックすると)、バインディング・オブジェクトによってイテレータに対して関連するメソッドが実行され、イテレータによって別の10個のレコードのセットが取得されます。その後、取得されたセットがバインディングによって使用されます。この設定は、必要に応じて変更できます。完全なレコード・セットを戻すには、-1
に設定します。リスト・バインディングの有効選択肢リストを提供するイテレータ・バインディングの場合、デフォルトは-1です。
表13-1は、データ・コントロールで提供される組込みナビゲーション操作、ページ定義で設定されるアクション属性値、および操作の起動または操作にバインドされたイベントの起動の結果を示しています。アクション・イベントの詳細は、13.4.3項「実行時の処理: アクション・イベントおよびアクション・リスナー」を参照してください。
操作 | アクション属性値 | 関連イテレータ・バインディングによる起動時の処理 |
---|---|---|
Next |
10 |
現在のポインタを結果セットの次のオブジェクトに移動します。このオブジェクトが現在のレンジの外にある場合は、レンジ・サイズと同じオブジェクト数だけレンジが進むようにスクロールされます。 |
Previous |
11 |
現在のポインタを結果セットの前のオブジェクトに移動します。このオブジェクトが現在のレンジの外にある場合は、レンジ・サイズと同じオブジェクト数だけレンジが戻るようにスクロールされます。 |
First |
12 |
現在のポインタを結果セットの最初に移動します。 |
Last |
13 |
現在のポインタを結果セットの最後に移動します。 |
Next Set |
14 |
レンジ・サイズ属性と同じオブジェクト数だけ、レンジを進めるように移動します。 |
Previous Set |
15 |
レンジ・サイズ属性と同じオブジェクト数だけ、レンジを戻すように移動します。 |
操作の各アクション・バインディングには、enabled
ブール型プロパティが含まれます。このプロパティは、操作を起動しない場合には、ADFフレームワークによってfalse
に設定されます。この値にUIコンポーネントをバインドすると、コンポーネントを有効化するかどうかを指定できます。enabled
プロパティの詳細は、付録B「ADFバインディング・プロパティのリファレンス」を参照してください。
ナビゲーション操作を使用してコマンド・コンポーネントを作成すると、作成したコンポーネントはpanelButtonBar
コンポーネント内に配置されます。JDeveloperによってEL式が作成され、この式によって、ナビゲーション・コマンド・ボタンのactionListener
属性が、指定された操作のアクション・バインディングのexecute
プロパティにバインドされます。ユーザーがボタンをクリックすると、この式によって、イテレータに対してバインディングの操作が起動されます。
コマンド・ボタンのactionListener
属性の詳細は、13.4.3項「実行時の処理: アクション・イベントおよびアクション・リスナー」を参照してください。たとえば、Firstコマンド・ボタンのactionListener
属性は、First
アクション・バインディングのexecute
メソッドにバインドされます。
disabled
属性は、ボタンを無効化するかどうかの判別に使用されます。たとえば、ユーザーが現在、最初のレコードを表示している場合は、「先頭へ」ボタンをクリックできないようにする必要があります。コードでは、アクション・バインディングのenabled
プロパティに対して評価するEL式が使用されます。プロパティ値がtrue
でない場合(たとえば、現在のレコードが最初のレコードで、First
操作の有効化が禁止されている場合)は、ボタンが無効になります。例13-10は、ナビゲーション操作ボタンに対してJSFページで生成されたコードを示しています。
例13-10 ADF操作にバインドされているナビゲーション・ボタンのJSFコード
<f:facet name="footer"> <af:panelButtonBar> <af:commandButton actionListener="#{bindings.First.execute}" text="First" disabled="#{!bindings.First.enabled}"/> <af:commandButton actionListener="#{bindings.Previous.execute}" text="Previous" disabled="#{!bindings.Previous.enabled}"/> <af:commandButton actionListener="#{bindings.Next.execute}" text="Next" disabled="#{!bindings.Next.enabled}"/> <af:commandButton actionListener="#{bindings.Last.execute}" text="Last" disabled="#{!bindings.Last.enabled}"/> </af:panelButtonBar> <af:commandButton text="Submit"/> </f:facet>
アクション・イベントは、コマンド・コンポーネントがアクティブになっているときに発生します。たとえば、ユーザーがボタンをクリックすると、そのコンポーネントが含まれているフォームが送信され、続いてアクション・イベントが起動します。アクション・イベントは、ユーザー・インタフェースのみに影響する場合(たとえば、異なるフィールド・プロンプトを表示させる、ロケールを変更するためのリンク)と、なんらかのロジック処理を伴う場合(たとえば、次のレコードに移動するためのボタン)があります。
アクション・リスナーは、コマンド・コンポーネントによってアクション・イベントが起動されたときに通知を必要とするクラスです。アクション・リスナーには、コマンド・コンポーネントによって渡されるアクション・イベント・オブジェクトを処理する、アクション・リスナー・メソッドが含まれます。
ナビゲーション操作の場合、ユーザーがたとえば「次へ」ボタンをクリックすると、アクション・イベントが起動します。このイベントは、イテレータから取得した現在のデータ・オブジェクトの現在行位置情報を格納します。コンポーネントのactionListener
属性がNext
アクション・バインディングのexecute
メソッドにバインドされているため、Next
操作が起動します。このメソッドは、イベント・オブジェクトで渡された現在行位置情報を使用して、次のデータ・オブジェクトを判別します。
ユーザーがナビゲーション・ボタンをクリックすると、イテレータによって次に表示するデータ・オブジェクトが判別されます。ただし、ユーザーがブラウザの「戻る」ボタンをクリックすると、アクションやイベントはブラウザ外で共有されず、イテレータが無視されます。つまり、ユーザーがページのナビゲーション・ボタンを使用するかわりにブラウザの「戻る」ボタンをクリックした場合は、表示されたページとイテレータが同期しなくなるため、予期しない結果が発生します。
たとえば、ユーザーがオブジェクト103を参照し、ブラウザの「戻る」ボタンを使用したとします。ブラウザは、最後に表示されたページを表示するため、ブラウザにオブジェクト102が表示されます。ただし、イテレータは無視されたため、イテレータの認識では、現在のオブジェクトは103のままです。その後、ユーザーが103を表示しようとして「次へ」ボタンをクリックすると、イテレータが次のオブジェクトとして認識している104が表示されます。
イテレータとページが同期していないため、ユーザーがレコードを編集する際に問題が生じます。たとえば、ユーザーがブラウザの「戻る」ボタンをクリックした後でオブジェクト102を編集すると、変更内容が103にポストされます。これは、イテレータが、103を現在のオブジェクトとして認識しているためです。
ユーザーが間違ったオブジェクト・インスタンスに変更を行うのを防ぐために、トークン検証を使用できます。ページのトークン検証を有効化すると、そのページのレンダリングに使用されるすべてのイテレータに対する現在のオブジェクトを使用して、ページに注釈が付けられます。この注釈は、ブラウザにレンダリングされたHTMLペイロードにエンコードされ、データとともにサーバーに送信されます。その時点で、イテレータの現在のオブジェクトが注釈と比較されます。一致していなかった場合は、例外がスローされます。
たとえば、前述の例のように、ユーザーが最初にオブジェクト103を表示し、102に移動しようとしてブラウザの「戻る」ボタンをクリックした場合は、前のページが表示されます。ただし、ページには102の注釈が付いています。そのため、ユーザーがページを送信して次のページに移動するつもりで「次へ」ボタンをクリックしても、注釈(102)がイテレータ(103のまま)と一致しないため、例外がスローされ、Next
操作は実行されません。ページは、イテレータの現在のオブジェクトである103を使用して、レンダリングされます。データを使用して送信された注釈に基づいて、サーバーでは102を予定していたため、ページには、102を予定していたことを示すエラー・メッセージが表示されます。現在は103が表示されているため、注釈とイテレータがともに現在は103で、再び同期された状態になります。
トークン検証は、JSFページのページ定義で設定されます。トークン検証は、デフォルトでオンになっています。
トークン検証の設定手順:
ページのページ定義ファイルを開きます。
構造ウィンドウで、ページ定義自体のルート・ノードを選択します。
プロパティ・インスペクタのEnableTokenValidation
属性のドロップダウン・リストを使用して、検証をtrueに設定してトークン検証をオンにするか、falseに設定してオフにします。
例13-11は、トークン検証がtrueに設定された後のページ定義ファイルを示しています。
ユーザーが現在のデータを編集し、その変更をデータ・ソースにコミットするためのフォームを作成できます。次に、コレクションに関連付けられた操作またはデータ・コントロール自体を使用して、データ・レコードの変更に使用されるコマンド・ボタンを作成します。たとえば、Delete
操作を使用して、ユーザーが現在のレンジからレコードを削除できるボタンを作成します。または、組込みの「発行」ボタンを使用して、変更を送信できます。
ヒント: フォーム上で作成操作を使用して、新規オブジェクトを作成することもできますが、「ADF作成フォーム」を使用すると追加の組込み機能が提供されます。詳細は、13.6項「入力フォームの作成」を参照してください。 |
重要なのは、これらの操作がADFキャッシュのオブジェクトに対してのみ実行されるという点です。ルート・データ・コントロール上でCommit
操作を使用して、任意の変更をデータ・ソースに実際にコミットする必要があります。データ・コントロールのRollback
操作を使用して、キャッシュされたオブジェクトに対する任意の変更をロールバックします。
フォーム上の操作を使用するには、ナビゲーション操作と同じ手順(13.4.1項「フォームへのナビゲーション・コントロールの挿入方法」を参照)に従いますが、データ・ストアで変更をコミットする、あるいはキャッシュをリストアするため、コミット操作およびロールバック操作のボタンも作成する必要があります。
編集フォームの作成方法:
データ・コントロール・パレットから、フォームを作成するコレクションをドラッグし、ポップアップ・メニューから「ADFフォーム」を選択します。
ユーザーが「フォーム・フィールドの編集」ダイアログでデータを変更できるようにするには、「送信ボタンを含める」を選択します。
操作の実行対象となるオブジェクトのコレクションに関連付けられている操作をデータ・コントロール・パレットから選択し、JSFページ上にドラッグします。
たとえば、サービス・リクエスト全体を削除できるようにする場合は、ServiceRequests
コレクションに関連付けられているDelete
操作をドラッグします。図13-8は、コレクションに関連付けられている操作を示しています。
ポップアップ・メニューから「コマンド・ボタン」または「コマンド・リンク」を選択します。
データ・コントロール・パレットから、ルート・レベル・データ・コントロールに関連付けられたCommit
操作とRollback
操作をドラッグし、コマンド・ボタンまたはコマンド・リンクのいずれかとしてドロップします。これにより、変更がコミットまたはロールバックされるようになります。図13-9に、SRService
データ・コントロールのコミット操作とロールバック操作を示します。
コマンド・ボタンとして任意のデータ・コントロール操作をドロップすると、ナビゲーション操作のドロップと同じイベントが発生します。詳細は、13.4.2項「データ・コントロール・パレットでコマンド・ボタンを作成した場合の処理」 を参照してください。
Commit
操作とRollback
操作はアプリケーション・モジュールでメソッドを実行するため、これらの操作のアクション・バインディングがイテレータへの参照を必要としないことが唯一の相違点です。例13-12に、これらの操作に対するページ定義ファイルに生成されたアクション・バインディングを示します。
例13-12 コミット操作とロールバック操作のアクション・バインディング
<action id="Commit" InstanceName="SRService" DataControl="SRService" RequiresUpdateModel="true" Action="100"/> <action id="Rollback" InstanceName="SRService" DataControl="SRService" RequiresUpdateModel="false" Action="101"/>
次の表は、データ・コントロールで可能な組込みのナビゲーション以外の操作と、その操作の起動結果または操作にバインドされたイベントの実行結果を示します(アクション・イベントの詳細は、13.4.3項「実行時の処理: アクション・イベントおよびアクション・リスナー」を参照してください)。
表13-2 追加の組込み操作
操作 | アクション属性値 | 関連イテレータ・バインディングによる起動時の処理 |
---|---|---|
Create |
41 |
現在行の直前に行を作成し、現在行のポインタを新規行に移動します。レンジは移動しません。つまり、レンジの最終行がレンジから除外される場合があります。また、この操作が実行するのは |
Delete |
30 |
キャッシュから現在行を削除し、現在行のポインタを結果セットの次の行に移動します。レンジは移動しません。つまり、行がレンジの最後に追加される場合があります。最終行が削除される場合は、現在行のポインタが前の行に移動します。コレクションに行がそれ以上ない場合は、有効な属性が「無効」に設定されます。 |
SetCurrentRowWithKey |
96 |
行キーを、入力フィールドで指定された値から変換された |
SetCurrentRowWithKeyValue |
98 |
キーの値を使用して、イテレータの現在のオブジェクトを設定します。 |
RemoveRowWithKey |
99 |
入力フィールドによって指定された値から変換された |
Commit |
100 |
現在キャッシュ内にあるすべての項目をデータベースにコミットします。 |
Rollback |
101 |
キャッシュをクリアして、トランザクションおよびイテレータを初期状態に戻します。 |
ExecuteおよびFind |
これらの操作は、検索フォームでのみ使用されます。詳細は、第18章「検索フォームの作成」を参照してください。 |
ユーザーが新規レコードの情報を入力し、そのレコードをデータソースにコミットするためのフォームを作成できます。デフォルトのADFフォームを使用して、作成操作をコマンド・ボタンとしてドロップすることもできますが、このタイプのフォームを最初にレンダリングする際には、コレクションの最初のインスタンスのデータが表示されます。「ADF作成フォーム」を使用すると、ユーザーは既存のインスタンスを最初に表示せずにコレクションの新規インスタンスを作成できます。
ただし、場合によっては、新規オブジェクトの作成方法をより詳細に制御する必要があります。たとえば、特定の属性にプログラム的に値を移入するとします。この場合、オブジェクトの作成を処理するカスタム・メソッドをアプリケーション・モジュール上で作成できます。カスタム・メソッドを使用して入力フォームを作成するには、「ADF作成フォーム」を使用するかわりに、標準フォームを使用してからコマンド・ボタンとしてカスタム・メソッドをドロップします。ユーザーがボタンをクリックすると、カスタム・メソッドが実行されます。
注意: プログラムで行を作成する場合、NewRow.setNewRowState(RowSet.STATUS_INITIALIZED メソッドをコールして、組込みのCreate アクションと同じ動作を取得する必要があります。詳細は、10.4.4項「CreateおよびCreateInsertについて」を参照してください。 |
その他のフォームの作成方法と同様に、入力フォームを作成します。ただし、コレクションをドロップする際に「ADF作成フォーム」を選択すると、JDeveloperでは追加機能が自動的に提供されます。
入力フォームの作成方法:
データ・コントロール・パレットから、フォームを作成するコレクションをドラッグし、ポップアップ・メニューから「ADF作成フォーム」を選択します。
「フォーム・フィールドの編集」ダイアログには、「発行」ボタンを含めないでください。
データ・コントロール・パレットから、ルート・データ・コントロールに関連付けられたコミット操作およびロールバック操作をドラッグし、コマンド・ボタンまたはリンクとしてドロップします。
構造ウィンドウで、コミット操作のコマンド・ボタンを選択します。
プロパティ・インスペクタで、コマンド・ボタンのDisabledプロパティをFalse
に設定します。
デフォルトでは、JDeveloperはボタンのDisabled
属性をバインディングのEnabled
プロパティにバインドします。これにより、Enabled
プロパティがFalse
に設定されると、ボタンが無効になります。このバインディングの場合、更新がポストされるまで、Enabled
プロパティはfalse
です。ユーザーに新しいオブジェクトを作成する必要が生じるまでは変更がポストされないため、入力フォームの目的上、ボタンは常に有効にしておく必要があります。
「ADF作成フォーム」を使用して入力フォームを作成すると、JDeveloperによって次の処理が行われます。
コレクションのイテレータ・バインディング、作成操作のアクション・バインディング、そしてコレクションのオブジェクトの各属性の属性バインディングを作成します。また、ページ定義の実行可能セクションに起動アクションが作成され、このアクションによって、このCreate
操作がモデル・レンダリング・フェーズで実行されます。Commit
操作およびRollback
操作を使用してコマンド・ボタンまたはリンクを作成した場合、JDeveloperではこれらの操作のアクション・バインディングも作成されます。
ADF Faces inputText
コンポーネント、および操作の場合はcommandButton
コンポーネントを使用して、JSFページにフォームのコードが挿入されます。
たとえば、SRDemoアプリケーションで製品の単純な入力フォームを作成するには、図13-10のように、データ・コントロール・パレットからProductsList
コレクションをADF作成フォームとしてドロップし、そのフォームの下に、コミット操作をボタンとしてドロップできます。
注意: この例で示したページは、実際のSRDemoアプリケーションには含まれていません。 |
例13-13は、この入力フォームのページ定義ファイルを示しています。起動アクションがレンダリング準備ライフサイクル・フェーズで実行されると、Create
操作が起動され、コレクションの新規インスタンスが作成されます。ライフサイクルの詳細は13.2.3項「実行時に行われる処理: JSFおよびADFのライフサイクル」を参照してください。
例13-13 作成フォームのページ定義コード
<executables> <iterator id="ProductListIterator" RangeSize="10" Binds="ProductList" DataControl="SRService"/> <invokeAction Binds="Create" id="invokeCreate" Refresh="renderModel" RefreshCondition="${!adfFacesContext.postback and empty bindings.exceptionsList}"/> </executables> <bindings> <action id="Create" RequiresUpdateModel="true" Action="41" IterBinding="ProductListIterator" InstanceName="SRServiceDataControl.ProductList" DataControl="SRServiceDataControl"/> <attributeValues id="ProdId" IterBinding="ProductListIterator"> <AttrNames> <Item Value="ProdId"/> </AttrNames> </attributeValues> <attributeValues id="Name" IterBinding="ProductListIterator"> <AttrNames> <Item Value="Name"/> </AttrNames> </attributeValues> <attributeValues id="Description" IterBinding="ProductListIterator"> <AttrNames> <Item Value="Description"/> </AttrNames> </attributeValues> <action id="Commit" InstanceName="SRServiceDataControl" DataControl="SRServiceDataControl" RequiresUpdateModel="true" Action="100"/> </bindings>
Create
操作が起動される場合は常に(たとえば、ページが最初にレンダリングされる場合)、データ・オブジェクトが作成されます。ただし、データがキャッシュされる(これにより、Create
操作によるサーバーへのポストバックが可能になる)ため、また、ページがrenderModel
フェーズになる場合はいつでもCreate
操作が起動されるため、Create
操作では、ユーザーが別のオブジェクト作成のためにこのページに再びアクセスすると、同一オブジェクトが再作成されます。また、エラーが発生すると、エラー・メッセージを使用してページが再レンダリングされるため、オブジェクトが再び作成されます。
複製を回避するために、起動アクションのrefreshCondition
プロパティは、サーバーへのポストバックが存在せず、エラー・メッセージがないかぎり、Create操作が1回しか起動されないように設定されています(EL式は例13-13を参照してください)。ユーザーが(アクション・バインディングによってコミット・アクションにバインドされる)「コミット」ボタンをクリックすると、データを持つ新規オブジェクトがデータソースに送信されます。ユーザーが同じページ上で複数のオブジェクトを作成できるようにするには、第13章「フォームの作成およびRefreshConditionについて」を参照してください。
ページが表示される前にinvokeCreate
アクションが実行されるため、順序を使用して主キー(この場合は製品ID)を移入する場合は、番号が入力テキスト・フィールドに表示されます。たとえば、空白にしておくかわりに、図13-10の製品IDに製品ID番号を表示します。これは、製品エンティティ・クラスに、Eagerフェッチを使用してprodId
属性の番号の順序を生成するメソッドが含まれるためです。これにより、行が作成される際に値が移入されます。
ただし、かわりに属性のタイプを(データベース・トリガーを使用して順序を生成する)DBSequenceに構成した場合、オブジェクトがデータベースにコミットされるまで番号は移入されません。この場合は、プレースホルダとして負の数が表示されます。この状態を回避するには、入力テキスト・フィールドのRendered
属性に次のEL式を使用できます。
#{bindings.EmployeeId.inputValue.value > 0}
この式は、値がゼロより大きい場合のみコンポーネントを表示します。これは、コミットの前ではなくなります。同様に、単純にRendered
属性をfalse
に設定できます。ただし、これによってページに主キーの入力テキスト・フィールド・コンポーネントが表示されなくなります。
ユーザーが入力フォームの「コミット」ボタンでページを閉じることができない場合は、そのページで最後のエントリからのデータ表示が再レンダリングされます。これは、invokeCreate
起動アクション上のrefreshCondition
(${!adfFacesContext.postback and empty bindings.exceptionsList}
)が、ポストバックがある場合にアクションが起動されなくなる原因となるためです。これは、データがコミットされる場合に該当します。
一度に複数の製品を作成するなど、ページ上にユーザーが留まることができるようにする場合は、refreshCondition
を変更して、新規オブジェクトをコミットした後にinvokeCreate
アクションを実行できるようにする必要があります。これを実行するために、Commitコマンド・コンポーネント内でsetActionListener
コンポーネントを使用します。setActionListener
コンポーネントを使用すると、移動する前にコマンド・コンポーネントによって値が設定されます。この場合、コマンド・コンポーネントはリクエスト・スコープ上でcreateAnother
という名前のフラグをtrue
に設定します。次の手順に示すように、refreshCondition
ではこのフラグを評価し、invokeCreate
アクションを実行するかどうかを判断できます。setActionListener
コンポーネントの詳細は、17.4.2項「パラメータの設定時に行われる処理」を参照してください。
複数オブジェクトを作成できる入力フォームの作成方法:
この手順に従って、入力フォームを作成します。
JSFページで、コンポーネント・パレットからsetActionListener
コンポーネントを「コミット」コマンド・ボタン上にドラッグします。
注意: この手順は、ユーザーがこの「コミット」ボタンをクリックした後、別のエントリを作成するために同じページに戻ることを前提にしています。これを反映するため、ボタンの名前をCommit and Create Anotherなどに変更する場合があります。ページを閉じるには、別のボタンを作成する必要があります。 |
「setActionListenerの挿入」ダイアログで、次の項目を設定します。
自: #{true}
至: #{requestScope.createAnother}
これにより、リクエスト・スコープ上でcreateAnother
という名前のフラグを作成し、それをtrue
に設定します。
JSFページのページ定義を開きます。
invokeCreate
起動アクションのrefreshCondition
を次のように変更します。
${!adfFacesContext.postback and empty bindings.exceptionsList}
変更後:
#{empty bindings.expressionList and (!adfFacesContext.postback or requestScope.createAnother)}
これにより、エラー・メッセージを含む式リストが空であり、ポストバックまたはリクエスト・スコープ上のcreateAnother
フラグがtrueに設定されている場合に、invokeCreate
アクションを実行する条件が設定されます。
注意: setActionListener コンポーネントは、ライフサイクルのアプリケーションの起動フェーズで実行します。このため、invokeCreate アクションのrefresh 属性を後続フェーズに設定する必要があります。この場合は、デフォルトでrenderModel に設定されるため変更しないでください。 |
データ・コントロール・パレットを使用してフォームを作成したら、属性の削除、表示順序の変更、表示に使用するコンポーネントの変更、およびバインド先の属性の変更を行えます。
データ・コントロール・パレットからドロップしたデフォルト・コンポーネントについて、一部の内容を変更することができます。構造ウィンドウを使用して、コンポーネントの表示順序の変更、新規コンポーネントの追加や既存のコンポーネントの変更、またはコンポーネントの削除を行えます。プロパティ・インスペクタを使用すると、バインディングの変更や削除、またはコンポーネントに対して表示されるラベルの変更を行えます。
デフォルト・コンポーネントおよびバインディングの変更の手順:
構造ウィンドウを使用して、次の処理を行います。
UIコンポーネントの順序の変更。ツリー内でUIコンポーネントを上下にドラッグします。矢印付きの黒い線は、UIコンポーネントが配置される場所を示しています。
新規属性のUIコンポーネントの追加。構造ウィンドウで既存のUIコンポーネントを右クリックし、新規コンポーネントの配置場所として、選択したコンポーネントの前、後ろ、内部のいずれかを選択します。その後、リストからUIコンポーネントを選択します。
新規コンポーネントを属性にバインドするには、プロパティ・インスペクタを使用する必要があります。詳細は、手順2の最初の項目を参照してください。
UIコンポーネントの削除。コンポーネントを右クリックして、「削除」を選択します。コンポーネントを残してバインディングのみを削除する場合は、プロパティ・インスペクタを使用する必要があります。手順2の2番目の項目を参照してください。
構造ウィンドウでUIコンポーネントを選択した後、プロパティ・インスペクタで次の処理を行えます。
UIコンポーネントのバインディングの追加。「値」フィールドにEL式を入力するか、「値」フィールドの省略記号(...)ボタンをクリックして、EL式ビルダーを開きます。データ・コントロールから使用できるバインディングを選択するには、「ADFバインディング」→「Bindings」ノードを選択します。このノードは、現在バインドされているコレクションから使用できる操作、イテレータ、属性、およびバインディング・プロパティを表示します。EL式の使用の詳細は、12.6項「ADFデータ・バインディングEL式の作成」を参照してください。
バインディングの変更。その他の属性または別の属性の任意のプロパティに、コンポーネントをリバインドできます。手順は、13.7.1.1項「UIコンポーネントの値バインディングの変更」を参照してください。
UIコンポーネントのラベルの変更。デフォルトでは、ラベルはバインディングのlabel
プロパティにバインドされています(このプロパティの詳細は、付録B「ADFバインディング・プロパティのリファレンス」を参照してください)。このプロパティにより、エンティティ・オブジェクト属性またはビュー・オブジェクト属性に対して定義したラベルのUIコントロール・ヒントをページで使用できるようになります。ここでは、値の1度の変更で、ラベルを表示するすべてのページに同じ値を表示できます。
現在のページのラベルのみを変更することもできます。その場合は、Label
属性を選択します。ラベル値を別のもの(たとえば、プロパティ・ファイルやリソース・ファイルのキー)にバインドするために、テキストまたはEL式を入力します。
たとえば、サービス・リクエストのステータスの入力に使用するinputText
コンポーネントでは、Label
属性に対して次のコードが含まれます。
#{bindings.Status.label}
この式のstatus
は、ページ定義ファイルの属性バインディングのIDです。
この式を変更して、プロパティ・ファイルのキーにバインドすることもできます。次に例を示します。
#{srproperties['sr.status']}
この例のsrproperties
は、プロパティ・ファイルのロードに使用する、JSFページで定義された変数です。SREditページでは、res
という変数が使用されます。取消ボタンのラベルには、次の値が設定されています。
#{res['srdemo.cancel']}
リソース・バンドルの使用方法の詳細は、22.4項「アプリケーションの国際化」を参照してください。
バインディングを変更するかわりに、フォーム内のUIコンポーネントがバインドされているオブジェクトを完全に変更することができます。
UIコンポーネントのリバインドの手順:
データ・コントロール・パレットから、コンポーネントの新しいバインド先となるコレクションまたは属性をドラッグし、コンポーネント上にドロップします。
または
構造ウィンドウでUIコンポーネントを右クリックし、「バインディングを編集」を選択します。バインディングを変更するUIコンポーネントに応じて、属性、表またはリストのバインディング・エディタが起動します。
ポップアップ・メニューから「既存の<コンポーネント名>のバインド」を選択します。