この章では、ADF Facesコンポーネントを使用した、データ・コントロール・パレットでのデータ・バインド・フォームの作成方法を説明します。
この章の内容は次のとおりです。
ビジネス・サービス用に作成されたデータ・コントロールを使用して情報の表示および収集を行うための、UIウィジェットを作成できます。たとえば、データ・コントロール・パレットを使用して、項目の属性をドラッグし、読取り専用テキストまたはラベル付き入力テキスト・フィールドとして、値を表示できます。
JDeveloperでは、属性を個別にドロップする必要はなく、オブジェクトのすべての属性をフォームとして一度にドロップできます。フォームを構成する実際のUIコンポーネントは、ドロップしたフォームのタイプによって異なります。
UIコンポーネントをドロップしたら、ユーザーがデータを操作できるようにするための組込み操作を、コマンドUIコンポーネントとしてドロップできます。たとえば、フォームに表示されたデータ・オブジェクト間をユーザーが移動できるようにするためのボタンを作成できます。また、必要に応じてデフォルトのコンポーネントを変更することもできます。
この章の内容は次のとおりです。
個々のデータ・バインド・テキスト・フィールドの作成方法
複数のテキスト・フィールドで構成されるフォームの作成方法
フォームに表示されるデータ・オブジェクト間を移動するための操作の追加方法
作成済フォームの変更方法
テキスト・フィールドを作成するには、属性バインディングを使用して、ADF FacesテキストUIコンポーネントをデータ・コントロールの属性にバインドします。JDeveloperでは、この処理をコードを記述せずに宣言的に行うことができます。また、JDeveloperには、JSFページ用の完全なWYSIWYG開発環境が用意されているため、ページのほとんどの内容をコードを見ずに設計することができます。
属性の表示または更新を行えるテキスト・フィールドを作成するには、データ・コントロールを使用して、UIコンポーネントを属性にバインドする必要があります。JDeveloperでは、データ・コントロール・パレットからコレクションの属性をドラッグ・アンド・ドロップして、この処理を宣言的に行えます。
バインドされたテキスト・フィールドの作成手順:
データ・コントロール・パレットからコレクションの属性を選択します(属性およびデータ・コントロール・パレットのその他のオブジェクトを表すアイコンの説明は、5.2.1項「データ・コントロール・パレットの各項目の理解」を参照してください)。
たとえば、図6-1は、SRDemoアプリケーションのSRPublicFacade
データ・コントロールに含まれているfindAllServiceRequest()
メソッドの、ServiceRequest
コレクションの下にあるproblemDescription
属性を示しています。この属性は、サービス・リクエストに対する問題の説明を表示する場合にドロップします。
データ収集に使用する入力テキストフィールドを作成する場合は、カスタム・メソッドまたはデータ・コントロールのいずれかの組込み作成メソッドを使用できます。手順は、10.7項「新規レコード用入力フォームの作成」を参照してください。
ページに属性をドラッグし、ポップアップ・メニューから、属性値を表示または収集するウィジェットのタイプを選択します。各属性について、次の選択肢があります。
テキスト
ラベル付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
コンポーネント。
単一選択
これらのウィジェットによって、リストが表示されます。この章の目的にあわせて、ここではテキスト・ウィジェットのみについて説明します。リストおよびそのバインディングの詳細は、11.7項「データ・バインドされたドロップダウン・リストの作成」を参照してください。
JSFページに属性をドラッグしてUIコンポーネントとしてドロップすると、そのページのページ定義ファイル(すでに存在する場合を除く)などが作成されます。ページ定義ファイルの名前として、ページのパッケージ名を含むJSFページの名前にPageDef
を追加したものが使用されます。たとえば、SREditページのページ定義ファイルはapp_staff_SREditPageDef.xml
です。属性をページにドラッグしたときに行われる処理の完全な説明は、5.2.3項「データ・コントロール・パレットの使用時に行われる処理」を参照してください。イテレータとメソッドのバインディングがまだ存在しない場合は、各属性のバインディングのように、このバインディングが作成されてページ定義ファイルに追加されます。また、UIコンポーネントに必要なJSPXページのコードがJSFページに追加されます。
データ・コントロール・パレットからコレクションの一部である項目をドロップして(またはコレクション全体をフォームまたは表としてドロップして)ページ上にUIコンポーネントを作成するたびに、メソッド・イテレータ・バインディングが自動的に作成されます(まだ存在しない場合)。メソッド・イテレータ・バインディングは、データ・コレクションのイテレータを参照し、そのデータ・オブジェクトの反復処理を容易にします。また、コレクション内のデータ・オブジェクトの現在行および状態を管理します。イテレータ・バインディングは実際にはデータにアクセスしません。かわりに、データにアクセスできるオブジェクトを単純に公開し、コレクション内の現在のデータ・オブジェクトを指定します。その後、現在のオブジェクトのデータを戻したり、オブジェクトのデータに対してアクションを実行するために、他のバインディングがこのイテレータ・バインディングを参照します。
ヒント: 各コレクションに対して1つのイテレータが作成されます。つまり、同じコレクションから2つの属性をドロップした場合(もしくは同じコレクションを2回ドロップした場合)は、同じイテレータが使用されます。コンポーネントごとに動作の異なるイテレータが必要な場合を除き、同じイテレータが使用されても問題はありません。異なるイテレータが必要な場合は、個別のイテレータを手動で作成する必要があります。その手順および例は、10.9項「検索ページの結果表の条件付き表示」を参照してください。 |
たとえば、findAllServiceRequest()
メソッドのServiceRequest
コレクションの下にあるproblemDescription
属性をドロップした場合、戻されたServiceRequest
コレクションのメソッド・イテレータ・バインディングが自動的に作成されます。
イテレータ・バインディングのrangeSize
属性は、イテレータ・バインディングへのアクセスが行われるたびにページで使用できるレコードの数を決定します。この属性により、行セット全体のいずれかの絶対開始位置に存在する1-N行の相対セットが提供されます。デフォルトでは10
に設定されています。この属性の使用方法は、6.4.2.2項「イテレータのRangeSize属性」を参照してください。例6-1は、findAllServiceRequest()
メソッドのServiceRequest
コレクションから属性をドロップすると作成されるメソッド・イテレータ・バインディングを示しています。
例6-1 メソッド戻りコレクションから属性をドロップした場合のメソッド・イテレータ・バインディングのページ定義コード
<executables> <methodIterator id="findAllServiceRequestIter" Binds="findAllServiceRequest.result" DataControl="SRPublicFacade" RangeSize="10" BeanClass="oracle.srdemo.model.entities.ServiceRequest"/> </executables>
イテレータ・バインディング要素の属性に関する詳細は、A.2.2項「Oracle ADFデータ・バインディング・ファイル」を参照してください。
また、JDeveloperによって、コレクションを戻すときに使用するfindAllServiceRequest
メソッドのアクション・バインディングも作成されます。このアクション・バインディングは、バインディング要素として作成されるもので、実行可能要素ではありません。例6-2は、findAllServiceRequest()
メソッドのServiceRequest
コレクションの属性をドロップすると作成されるアクション・バインディングを示しています。
例6-2 イテレータによって使用されるアクション・バインディングのページ定義コード
<bindings> <methodAction id="findAllServiceRequest" InstanceName=""SRPublicFacade.dataProvider" DataControl="SRPublicFacade" MethodName="findAllServiceRequest" RequiresUpdateModel="true" Action="999" ReturnName="SRPublicFacade.methodResults.SRPublicFacade_ dataProvider_findAllServiceRequest_result"/>
このメタデータは、関連付けられているメソッド・バインディングの結果プロパティにイテレータがアクセスできるようにすることで、ADFバインディング・コンテナによる属性へのアクセスを可能にします。このイテレータは実行可能で、ページのロード時に作成されるため、これによってメソッド・バインディングで参照されるメソッドが実行されます。
例6-1のイテレータは、findAllServiceRequest
メソッド・バインディングの結果プロパティにバインドされています。これは、戻されたサービス・リクエストがすべてこのイテレータによって管理されることを意味します。現在のサービス・リクエストやサービス・リクエストのレンジの判別も含まれます。
アクション・バインディング要素の属性に関する詳細は、A.2.2項「Oracle ADFデータ・バインディング・ファイル」を参照してください。
データ・コントロール・パレットから属性をドロップすると、JDeveloperによって、UIコンポーネントを属性の値にバインドするための属性バインディングが作成されます。このタイプのバインディングは、コレクション内の現在行のシングル・オブジェクトに対する属性の値を提示します。値バインディングは、属性値の表示と収集の両方に使用できます。
たとえば、findAllServiceRequest()
メソッドのServiceRequest
コレクションの下にあるproblemDescription
属性を「ラベル付ADF出力テキスト」ウィジェットとしてSREditページにドロップすると、JDeveloperによって、problemDescription
属性の属性バインディングが作成されます。この属性値は、findAllServiceRequest
Iter
イテレータを参照します。これにより、バインディングが現在のレコードの属性値にアクセスできるようになります。例6-3は、findAllServiceRequest()
メソッドのServiceRequest
コレクションの属性をドロップすると作成されるproblemDescription
の属性バインディングを示しています。
例6-3 属性バインディングのページ定義コード
<bindings> ... <attributeValues id="ServiceRequestproblemDescription" IterBinding="findAllServiceRequestIter"> <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データ・バインディング・ファイル」を参照してください。
例6-4は、属性をラベル付き出力テキスト・ウィジェットとしてドロップしたときに、JSFページで生成されるコードを示しています。
例6-4 ラベル付き出力テキストとしてドロップされた属性のJSFページ・コード
<af:panelLabelAndMessage label="#{bindings.ServiceRequestproblemDescription.label}"> <af:outputText value="#{bindings.problemDescription.inputValue}"/> </af:panelLabelAndMessage>
problemDescription
属性をラベル付き入力テキスト・ウィジェットとしてドロップすると、JDeveloperによって、inputText
コンポーネントが作成されます。例6-5に示すとおり、出力テキスト・コンポーネントと同様に、値はproblemDescription
バインディングのinputValue
プロパティにバインドされます。また、次のプロパティも設定されます。
label
: バインディングのlabel
プロパティにバインドされます。
required
: バインディングのmandatory
プロパティにバインドされます。このプロパティの詳細は、12.3項「検証の追加」を参照してください。
columns
: displayWidth
プロパティにバインドされます。テキスト・ボックスの幅を決定します。
例6-5 ラベル付き入力テキストとしてドロップされた属性のJSFページ・コード
<af:inputText value="#{bindings.problemDescription.inputValue}" label="#{bindings.problemDescription.label}" required="#{bindings.problemDescription.mandatory}" columns="#{bindings.problemDescription.displayWidth}"> <af:validator binding="#{bindings.problemDescription.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
に追加されます。例6-6は、faces-config.xml
でのADF PhaseListenerの構成を示しています。
例6-6 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>
図6-2は、JSFおよびADFのフェーズがライフサイクルの中でどのように統合されるかを示しています。
ADFモデル・レイヤーを使用するJSFアプリケーションでは、ライフサイクルは次のようになります。
ビューのリストア: リクエストされたページのURLがbindingContext
に渡され、URLと一致するページ定義が検索されます。リクエストされたページのコンポーネント・ツリーが、新しく作成されるかリストアされます。送信されたページ上のすべてのコンポーネント・タグ、イベント・ハンドラ、コンバータおよびバリデータは、FacesContext
インスタンスにアクセスできます。ツリーが新しく、空の場合(つまり、送信されたページからのデータがない)は、ライフサイクルは直接レスポンスのレンダリング・フェーズに進みます。それ以外の場合は、ビューのリストア・フェーズによって、ADFモデル・レイヤーのコンテキストの初期化フェーズがリスニングするイベントが発行され、実行されます。
たとえば、ページに含まれているinputText
UIコンポーネントがServiceRequest
戻りコレクションのProblemDescription
属性にバインドされている場合、URLが渡されると、そのページ定義が公開されます。その後、UIコンポーネントが作成されます。データが表示される場合は、コンテキストの初期化フェーズが実行されます。表示されない場合は、ライフサイクルがレスポンスのレンダリング・フェーズに進みます。
コンテキストの初期化: ページ定義ファイルを使用してbindingContainer
オブジェクトが作成されます。このオブジェクトは、リクエストされたページのページ定義の実行時表現です。ADFライフサイクルの全フェーズの情報を保存するために使用されるLifecycleContext
クラスがインスタンス化され、初期化されます。
モデルの準備: バインディング・コンテナがリフレッシュされ、ページ定義に含まれるすべてのページ・パラメータが設定されます。Refresh
属性およびRefreshCondition
属性の値に基づいて、ページ定義の実行可能セクションに含まれるすべてのエントリがリフレッシュされます。
Refresh
属性およびRefreshCondition
属性は、実行可能なバインディングを起動するかどうか、およびいつ起動するかを決定するのに使用されます。たとえば、一定の条件下でのみ起動される実行可能なバインディングが存在することがあります。この場合、Refresh属性により実行可能なバインディングの起動フェーズが決定され、RefreshCondition属性により条件に一致しているかどうかが決定されます。バインディングが操作の結果に依存する場合は、Refresh
属性をprepareModel
に設定します。
Refresh
がprepareModel
に設定されているか、値が指定されていない(つまり、デフォルトのifneeded
が使用される)場合は、RefreshCondition
属性値が評価されます。RefreshCondition
値が存在しない場合は、実行可能セクションが起動します。RefreshCondition
の値が存在する場合は、値が評価され、評価の戻り値がtrueの場合は、実行可能セクションが起動します。値がfalseと評価された場合は、実行可能セクションは起動しません。デフォルト値は常に、実行を強制します。受け取ったリクエストにPOSTデータまたは問合せパラメータが含まれていない場合、ライフサイクルはレスポンスのレンダリング・フェーズに進みます。
詳細は、イテレータ・バインディングのRefreshプロパティの適切な構成に関する項を参照してください。リフレッシュ属性の詳細は、A.7.1項「PageDef.xmlの構文」を参照してください。
問題の説明の例では、bindingContainer
によってfindAllServiceRequestIter
メソッド・イテレータが起動され、次に、ServiceRequest
コレクションを戻すfindAllServiceRequest
メソッドが起動されます。その後、イテレータによってデータが反復処理され、最初に検出されたレコードのデータがバインディング・コンテナに配置されて、UIコンポーネントで使用できるようになります。イテレータからの値にアクセスできるページ定義内のproblemDescription
属性にバインディングが設定されているため(例6-3を参照)、また、EL式(#{bindings.problemDescription.inputValue}
)を使用してUIコンポーネントがproblemDescription
バインディングにバインドされているため、そのデータがコンポーネントによって表示されます。
リクエスト値の適用: ツリー内の各コンポーネントにより、リクエスト・パラメータから(そのデコード・メソッドを使用して)新しい値が抽出され、ローカルに格納されます。関連付けられているほとんどのイベントは、後の処理のためにキューされます。コンポーネントのimmediate
属性がtrue
に設定されている場合は、コンポーネントに関連付けられている検証、変換およびイベントが、このフェーズで処理されます。検証および変換の詳細は、第12章「検証と変換の使用」を参照してください。
たとえば、ユーザーがinputText
コンポーネントに新しい値を入力すると、その値はinputText
コンポーネントのsetSubmittedValue
メソッドを使用してローカルに格納されます。
処理の検証: コンポーネントのローカルの値が変換され、検証されます。エラーが発生した場合は、ライフサイクルがレスポンスのレンダリング・フェーズに進みます。このフェーズの最後に、コンポーネントの新しい値が設定され、検証または変換のエラー・メッセージおよびイベントがFacesContext
でキューされて、すべての値変更イベントが配信されます。
ライフサイクルのこのフェーズおよび後続の2つのフェーズの詳細な説明は、第12章「検証と変換の使用」を参照してください。
アプリケーションの起動: コマンド・コンポーネントまたはイベントのアクション・バインディングが起動されます。ライフサイクルのこのフェーズおよび後続の2つのフェーズの詳細な説明は、9.4項「動的ナビゲーションの使用」を参照してください。ビジネス・ロジックの起動に使用されるアクション・バインディングの説明は、6.4項「レンジ・ナビゲーションのフォームへの組入れ」を参照してください。
メタデータのコミット: 実行時メタデータへの変更がコミットされます。このフェーズは今回のリリースでは使用されていませんが、将来のリリースで使用されます。
コンテキストの初期化(アプリケーションの起動ライフサイクルでナビゲーションが発生した場合のみ): 次のページのページ定義が初期化されます。
モデルの準備(アプリケーションの起動ライフサイクルでナビゲーションが発生した場合のみ): 次のページの定義に含まれるすべてのページ・パラメータが設定されます。ページ定義の実行可能セクションに含まれるすべてのエントリを使用して、対応するメソッドが表示順に起動されます。
レンダリングの準備: バインディング・コンテナがリフレッシュされ、リクエスト値の適用フェーズまたは検証フェーズで発生したすべての変更が反映されます。登録されたすべてのリスナーに、prepareRender
イベントが送信されます。
注意: JDeveloperでは、選択用の有効なフェーズとしてprepareRender は表示されず、バインディング・コンテナでコールされるrefresh(RENDER_MODEL) メソッドを表すrenderModel が表示されます。 |
refreshCondition
がモデルに依存する場合は、実行可能セクションのRefresh
属性をrenderModel
に設定する必要があります。たとえば、実行可能セクションのRefreshCondition
で#{adfFacesContext.postback}
式を使用する場合は、Refresh
プロパティをrenderModel
またはrenderModelIfNeeded
に設定する必要があります。これにより、prepareRender
フェーズ中にメソッドが実行されます。詳細は、イテレータ・バインディングのRefreshプロパティの適切な構成に関する項を参照してください。
レスポンスのレンダリング: J2EE Webコンテナがページ内のタグを横断するにつれて、ツリー内のコンポーネントがレンダリングされます。後続のリクエストおよびビューのリストア・フェーズ用に、状態の情報が保存されます。
JDeveloperでは、属性を個別にドロップしてフォームを作成するのではなく、オブジェクトのすべての属性のデータを表示または収集する、完全なフォームをドロップできます。たとえば、SREditページは、指定されたサービス・リクエストの編集に必要なすべての属性が含まれているfindServiceRequestById
メソッドからの戻りをドロップして作成されています。
このセクションでは、表示または編集するデータを戻すフォームの作成に関する情報を提供します。また、コンストラクタまたはメソッド自体を使用して、戻りデータのかわりにデータの移入に使用されるフォームを作成できます。このようなフォームの作成方法の詳細は、10.7項「新規レコード用入力フォームの作成」を参照してください。
データ・コントロールを使用してフォームを作成するには、UIコンポーネントをデータ・コントロールの対応するオブジェクトの属性にバインドします。JDeveloperでは、データ・コントロール・パレットからコレクションまたは構造化された属性をドラッグ・アンド・ドロップして、この処理を宣言的に行えます。
これらの手順は、パラメータを取得しないメソッドによって戻されたコレクションのすべてのオブジェクトを表示するフォームの作成に適用されます。パラメータを取得するメソッドから戻されたコレクションを使用する場合は、これらのパラメータを設定して、フォームに適切なレコードが表示されるようにする必要があります。パラメータの設定の手順および情報は、10.6.1項「パラメータを取得するメソッドを使用したフォームまたは表の作成方法」を参照してください。
ユーザーが新規レコードを作成できるフォームを作成するには、インスタンスの値を指定すると新規インスタンスが作成されるメソッドを使用する必要があります。データ・コントロールの構成により更新がサポートされている場合は、データ・コントロールにコンストラクタが含まれます。コンストラクタは、新規オブジェクトを作成するフォームの作成に使用できるオブジェクトで、オブジェクトのすべての属性の値が移入されます。詳細は、10.7項「新規レコード用入力フォームの作成」を参照してください。
コレクション、コンストラクタ、メソッドのいずれを使用してフォームを作成する場合でも、データソースにデータを挿入するメソッドや、データを更新するメソッドなどを起動する、コマンド・ボタンを追加することができます。手順および詳細は、10.3項「メソッドを実行するためのコマンド・コンポーネントの作成」を参照してください。
基本的なフォームの作成手順:
データ・コントロール・パレットから、findAll
メソッドの戻りであるコレクションを選択します。
既存の属性の値を表示するには、レコードの検索に使用したメソッドから戻されたコレクションをドロップします。図6-3は、SRDemoアプリケーションのfindAllServiceRequest()
メソッドのServiceRequest
コレクションを示しています。このメソッドによって作成されるフォームの入力テキスト・フィールドには、すでにデータが移入されています。
ページにコレクションをドラッグし、ポップアップ・メニューから、オブジェクトのデータを表示または収集するフォームのタイプを選択します。各フォームについて、次の選択肢があります。
ADFフォーム: 「フォーム・フィールドの編集」ダイアログが開き、デフォルトですべての属性に対して1つのフィールドを作成するのではなく、属性を個別に選択できます。また、各属性に使用するラベルおよびUIコンポーネントを選択できます。デフォルトでは、ADF inputText
コンポーネントが使用されますが、例外として、日付にはselectInputDate
コンポーネントが使用されます。各inputText
コンポーネントには、属性の検証を設定するためのバリデータ・タグが含まれます。詳細は、12.3項「検証の追加」を参照してください。
ユーザーがコレクション内の全データ・オブジェクト間を移動できるようにする、ナビゲーション・コントロールを含めることもできます。詳細は、6.4項「レンジ・ナビゲーションのフォームへの組入れ」を参照してください。必要に応じて、フォームを送信するための「発行」ボタンを含めることもできます。このボタンにより、HTMLフォームを送信し、JSF/ADFページ・ライフサイクルの一環としてフォームのデータをバンディングに適用します。このダイアログの使用方法に関する追加のヘルプを表示するには、「ヘルプ」をクリックします。すべてのUIコンポーネントは、panelForm
コンポーネントの中に配置されます。
ADF読取り専用フォーム: 「ADFフォーム」と同じですが、デフォルトではoutputText
コンポーネントが使用されます。このフォームはデータの表示を目的としているため、validator
タグは追加されません。各コンポーネントのlabel
属性に値が移入されます。タイプDate
の属性でも、outputText
コンポーネントが使用されます。すべてのコンポーネントはpanelLabelAndMessage
コンポーネントの中に配置され、panelLabelAndMessage
コンポーネントはpanelForm
コンポーネントの中に配置されます。
ADF作成フォーム: TopLink JavaオブジェクトおよびEJBセッションBeanの使用時には使用されません。かわりにコンストラクタ・メソッドまたはカスタム・メソッドを使用します。詳細は、10.7項「新規レコード用入力フォームの作成」を参照してください。
ユーザーがデータを更新できるようにするためのフォームを作成する場合は、ここで、更新を実行するメソッドをドラッグ・アンド・ドロップする必要があります。詳細は、10.3項「メソッドを実行するためのコマンド・コンポーネントの作成」を参照してください。
データ・コントロール・パレットからオブジェクトをフォームとしてドロップすることは、単一の属性をドロップするのと同じ効果があります。ただし、複数の属性バインディングと関連するUIコンポーネントが作成される点が異なります。UIコンポーネントの属性(value
など)は、その属性のバインディング・オブジェクト(inputValue
など)のプロパティにバインドされます。例6-7は、findAllServiceRequest()
メソッドのServiceRequest
コレクションをデフォルトのADFフォームとしてドロップした場合にJSFページで生成されるコードを示しています。
例6-7 入力フォームの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}"/> <f:convertNumber groupingUsed="false" pattern="#{bindings.svrId.format}"/> </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:inputText value="#{bindings.problemDescription.inputValue}" label="#{bindings.problemDescription.label}" required="#{bindings.problemDescription.mandatory}" columns="#{bindings.problemDescription.displayWidth}"> <af:validator binding="#{bindings.problemDescription.validator}"/> </af:inputText> <af:selectInputDate value="#{bindings.assignedDate.inputValue}" label="#{bindings.assignedDate.label}" required="#{bindings.assignedDate.mandatory}"> <af:validator binding="#{bindings.assignedDate.validator}"/> <f:convertDateTime pattern="#{bindings.assignedDate.format}"/> </af:selectInputDate> <f:facet name="footer"> <af:commandButton text="Submit"/> </f:facet> </af:panelForm>
JSFコンポーネントでは、ファセット・タグを使用して、親コンポーネントとの特別な関係が要求される他のコンポーネント(たとえば、表の列のヘッダーとフッター、またはpanelForm
コンポーネントのfooter
)が保持されます。データ・コントロール・パレットを使用してウィジェットをドロップすると、デフォルトのファセットが組み込まれます。
ファセットは多くのコンポーネントで使用されます。ウィジェットを使用して複雑なコンポーネント(panelForm
など)を作成する際には、多くの場合、出力タグが自動的に作成され、ファセットに挿入されます。これらのコンポーネントを手動で編集するか、他のコンポーネントをファセットに追加できます。
コレクションを入力フォームとしてドロップする際に「発行」ボタンを含めることを選択した場合は、コマンド・ボタンがpanelForm
のfooter
ファセットに追加されます。このコマンド・ボタンによって、panelForm
を保持するフォームが送信されます。デフォルトでは、テキストは「発行」になります。図6-4は、panelForm
のfooter
ファセットのコマンド・ボタンを示しています。
例6-8は、JSFページの対応するコードを示しています。
例6-8 JSFページのファセット
<af:panelForm> ... <f:facet name="footer"> <af:commandButton text="Submit"/> </f:facet> </af:panelForm>
各ファセットで保持できるのは1つのコンポーネントのみです。複数のコンポーネントを保持するファセットが必要な場合は、複数のコンポーネントを1つのコンテナ・コンポーネントにネストし、ファセットにネストできる状態にする必要があります。たとえば、panelGroup
コンポーネントとpanelButtonBar
コンポーネントは、フォームのfooter
ファセットにあるすべてのボタンのグループ化に使用されています。これに関する詳細は、6.4.2.3項「EL式を使用したナビゲーション操作へのバインド」を参照してください。
また、コンポーネントに使用できるすべてのファセットは、構造ウィンドウに自動的に表示されます。ただし、アクティブな状態で表示されるのは、UIコンポーネントを含むファセットのみです。空のファセットはグレー表示されます。図6-5は、panelPage
コンポーネントの完全なファセットと空のファセットの両方を示しています。
データ・コントロール・パレットで入力フォームを作成する際にナビゲーションの追加を選択すると、JDeveloperによって、データ・コントロールの既存のナビゲーション・ロジックにバインドされているADF Facesコマンド・コンポーネントが組み込まれます。この組込みロジックによって、ユーザーは、コレクション内のデータ・オブジェクト全体を移動できるようになります。図6-6は、ナビゲーション・ボタンを含むフォームを示しています。
デフォルトでは、データ・コントロール・パレットを使用してフォームを作成する際にナビゲーションを含めることを選択すると、JDeveloperによって、「先頭へ」、「最後へ」、「前へ」および「次へ」の各ボタンが作成され、ユーザーがコレクション内を移動できるようになります。
また、既存のフォームに手動でナビゲーション・ボタンを追加することもできます。
ナビゲーション・ボタンを手動で追加する場合の手順:
操作の実行対象となるオブジェクトのコレクションに関連付けられている操作をデータ・コントロール・パレットから選択し、JSFページ上にドラッグします。
たとえば、サービス・リクエスト全体を移動できるようにする場合は、findAllServiceRequest()
メソッドのServiceRequest
コレクションに関連付けられている「次へ」操作をドラッグします。図6-7は、コレクションに関連付けられているナビゲーション操作を示しています。
ポップアップ・メニューから「コマンド・ボタン」または「コマンド・リンク」を選択します。
操作をコマンド・コンポーネントとしてドロップすると、JDeveloperによって次の処理が行われます。
関連付けられている操作について、ページ定義ファイルでアクション・バインディングが定義されます。
コマンド・コンポーネント用のコードがJSFページに挿入されます。
アクション・バインディングは、ビジネス・ロジックを実行します。アクション・バインディングは、ビジネス・サービスに対してメソッドを起動するか(たとえば、コレクションへのアクセスにイテレータが使用するメソッドのメソッド・アクション・バインディング)、ナビゲーション・コントロールの場合のように、アクション・バインディング・オブジェクトに対して組込みメソッドを起動できます。このような組込みメソッドは、イテレータやデータ・コントロール自体に対して作用し、データ・コントロール・パレットに操作として表示されます。ユーザーは、JDeveloperによって提供されるナビゲーション操作を使用して、コレクション内の前後のオブジェクトに移動したり、最後または最初のオブジェクトに移動できます。
値バインディングのように、ナビゲーション操作のアクション・バインディングにも、イテレータ・バインディングの参照が含まれている必要があります。この参照は、現在のオブジェクトの判別に使用され、これによって、各ナビゲーション・ボタンがクリックされたときに表示するオブジェクトが正しく判別されます。例6-9は、ナビゲーション操作のアクション・バインディングを示しています。
ヒント: <action> タグのAction 属性の数値(例6-9を参照)は、oracle.adf.model.meta.OperationDefinition クラスで定義されています。ただし、ADFモデル・レイヤーのアクション・バインディング・エディタを使用する場合は、手動で数値コードを設定する必要はありません。 |
例6-9 操作アクション・バインディングのページ定義コード
<action id="First" RequiresUpdateModel="true" Action="12" IterBinding="findAllServiceRequestIterator"/> <action id="Previous" RequiresUpdateModel="true" Action="11" IterBinding="findAllServiceRequestIterator"/> <action id="Next" RequiresUpdateModel="true" Action="10" IterBinding="findAllServiceRequestIterator"/> <action id="Last" RequiresUpdateModel="true" Action="13" IterBinding="findAllServiceRequestIterator"/>
イテレータ・バインディングには、各イテレータに対して戻されるデータ・オブジェクト数を決定するrangeSize
属性が含まれています。この属性は、データソース内のオブジェクト数がきわめて多い場合に役立ちます。すべてのオブジェクトではなく、1つのセット番号のみが戻され、他のバインディングによるアクセスが可能になります。イテレータは、レンジの最後に到達すると、別のセットにアクセスして新しいレンジを作成します。例6-10は、findAllServiceRequestIter
イテレータのレンジ・サイズを示しています。
例6-10 イテレータのRangeSize属性
<executables>
<methodIterator id="findAllServiceRequestIter"
Binds="findAllServiceRequest.result"
DataControl="SRPublicFacade" RangeSize="10"
BeanClass="oracle.srdemo.model.entities.ServiceRequest"/>
</executables>
デフォルトでは、rangeSize
属性は10
に設定されています。つまり、ユーザーは、データソースにアクセスせずに、前後に移動しながら10個のオブジェクトを表示できます。イテレータは、現在のオブジェクトを追跡します。ユーザーが新しいレンジが要求されるボタンをクリックすると(たとえば、オブジェクト番号10で「次へ」ボタンをクリックすると)、バインディング・オブジェクトによってイテレータに対して関連するメソッドが実行され、イテレータによって別の10個のレコードのセットが取得されます。その後、取得されたセットがバインディングによって使用されます。この設定は、必要に応じて変更できます。完全なレコード・セットを戻すには、-1
に設定します。リスト・バインディングに有効な選択リストを提供するイテレータ・バインディングの場合、デフォルトは-1です。
ヒント: ビジネス・サービスに記述する問合せで、レコードのレンジを直接設定することもできます。ただし、この方法では、この問合せを使用するすべてのページで同じレンジ・サイズが戻されることになります。イテレータにレンジ・サイズを設定することで、ページごとのサイズを管理できます。 |
表6-1は、データ・コントロールで提供される組込みナビゲーション操作、ページ定義で設定されるアクション属性値、および操作の起動または操作にバインドされたイベントの起動の結果を示しています。アクション・イベントの詳細は、6.4.3項「実行時に行われる処理: アクション・イベントおよびアクション・リスナー」を参照してください。
操作 | アクション属性値 | 関連イテレータ・バインディングによる起動時の処理 |
---|---|---|
Next |
10 |
現在のポインタを結果セットの次のオブジェクトに移動します。このオブジェクトが現在のレンジの外にある場合は、レンジ・サイズと同じオブジェクト数だけレンジが進むようにスクロールされます。 |
Previous |
11 |
現在のポインタを結果セットの前のオブジェクトに移動します。このオブジェクトが現在のレンジの外にある場合は、レンジ・サイズと同じオブジェクト数だけレンジが戻るようにスクロールされます。 |
First |
12 |
現在のポインタを結果セットの最初に移動します。 |
Last |
13 |
現在のポインタを結果セットの最後に移動します。 |
Next Set |
14 |
レンジ・サイズ属性と同じオブジェクト数だけ、レンジを進めるように移動します。 |
Previous Set |
15 |
レンジ・サイズ属性と同じオブジェクト数だけ、レンジを戻すように移動します。 |
SetCurrentRowWithKey |
96 |
行キーを、入力フィールドで指定された値から変換された |
SetCurrentRowWithKeyValue |
98 |
キーの値を使用して、イテレータの現在のオブジェクトを設定します。 |
操作の各アクション・バインディングには、enabled
ブール型プロパティが含まれます。このプロパティは、操作を起動しない場合には、ADFフレームワークによってfalse
に設定されます。この値にUIコンポーネントをバインドすると、コンポーネントを有効化するかどうかを指定できます。enabled
プロパティの詳細は、付録B「ADFバインディング・プロパティのリファレンス」を参照してください。
ナビゲーション操作を使用してコマンド・コンポーネントを作成すると、作成したコンポーネントはpanelButtonBar
コンポーネント内に配置されます。JDeveloperによってEL式が作成され、この式によって、ナビゲーション・コマンド・ボタンのactionListener
属性が、指定された操作のアクション・バインディングのexecute
プロパティにバインドされます。ユーザーがボタンをクリックすると、この式によって、イテレータに対してバインディングの操作が起動されます。
コマンド・ボタンのactionListener
属性の詳細は、6.4.3項「実行時に行われる処理: アクション・イベントおよびアクション・リスナー」を参照してください。たとえば、Firstコマンド・ボタンのactionListener
属性は、First
アクション・バインディングのexecute
メソッドにバインドされます。
disabled
属性は、ボタンを無効化するかどうかの判別に使用されます。たとえば、ユーザーが現在、最初のレコードを表示している場合は、「先頭へ」ボタンをクリックできないようにする必要があります。コードでは、アクション・バインディングのenabled
プロパティに対して評価するEL式が使用されます。プロパティ値がtrue
ではない場合(たとえば、現在のレコードが最初のレコードで、First
操作を有効化してはいけない場合)は、ボタンが無効になります。例6-11は、ナビゲーション操作ボタンに対してJSFページで生成されたコードを示しています。
例6-11 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に設定してオフにします。
例6-12は、トークン検証がtrueに設定された後のページ定義ファイルを示しています。
データ・コントロール・パレットを使用してフォームを作成したら、属性の削除、表示順序の変更、表示に使用するコンポーネントの変更、およびバインド先の属性の変更を行えます。
データ・コントロール・パレットからドロップしたデフォルト・コンポーネントについて、一部の内容を変更することができます。構造ウィンドウを使用して、コンポーネントの表示順序の変更、新規コンポーネントの追加や既存のコンポーネントの変更、またはコンポーネントの削除を行えます。プロパティ・インスペクタを使用すると、バインディングの変更や削除、またはコンポーネントに対して表示されるラベルの変更を行えます。
デフォルト・コンポーネントおよびバインディングの変更の手順:
構造ウィンドウを使用して、次の処理を行います。
UIコンポーネントの順序の変更。ツリー内でUIコンポーネントを上下にドラッグします。矢印付きの黒い線は、UIコンポーネントが配置される場所を示しています。
新規属性のUIコンポーネントの追加。構造ウィンドウで既存のUIコンポーネントを右クリックし、新規コンポーネントの配置場所として、選択したコンポーネントの前、後ろ、内部のいずれかを選択します。その後、リストからUIコンポーネントを選択します。
新規コンポーネントを属性にバインドするには、プロパティ・インスペクタを使用する必要があります。詳細は、手順2の最初の項目を参照してください。
UIコンポーネントの削除。コンポーネントを右クリックして、「削除」を選択します。コンポーネントを残してバインディングのみを削除する場合は、プロパティ・インスペクタを使用する必要があります。手順2の2番目の項目を参照してください。
構造ウィンドウでUIコンポーネントを選択した後、プロパティ・インスペクタで次の処理を行えます。
UIコンポーネントのバインディングの追加。「値」フィールドにEL式を入力するか、「値」フィールドの省略記号(...)ボタンをクリックして、EL式ビルダーを開きます。データ・コントロールから使用できるバインディングを選択するには、「ADFバインディング」→「Bindings」ノードを選択します。このノードは、現在バインドされているコレクションから使用できる操作、イテレータ、属性、およびバインディング・プロパティを表示します。EL式の使用方法の詳細は、5.6項「ADFデータ・バインディングEL式の作成」を参照してください。
バインディングの変更。その他の属性または別の属性の任意のプロパティに、コンポーネントをリバインドできます。手順は、6.5.1.1項「UIコンポーネントの値バインディングの変更」を参照してください。
UIコンポーネントのラベルの変更。デフォルトでは、ラベルはバインディングのlabel
プロパティにバインドされています(このプロパティの詳細は、付録B「ADFバインディング・プロパティのリファレンス」を参照してください)。
現在のページのラベルのみを変更することもできます。その場合は、Label
属性を選択します。ラベル値を別のもの(たとえば、プロパティ・ファイルやリソース・ファイルのキー)にバインドするために、テキストまたはEL式を入力します。
たとえば、サービス・リクエストのステータスの入力に使用するinputText
コンポーネントでは、Label
属性に対して次のコードが含まれます。
#{bindings.status.label}
この式のstatus
は、ページ定義ファイルの属性バインディングのIDです。
この式を変更して、プロパティ・ファイルのキーにバインドすることもできます。次に例を示します。
#{srproperties['sr.status']}
この例のsrproperties
は、プロパティ・ファイルのロードに使用する、JSFページで定義された変数です。SREditページでは、res
という変数が使用されます。取消しボタンのラベルには、次の値が設定されています。
#{res['srdemo.cancel']}
リソース・バンドルの使用方法の詳細は、14.4項「アプリケーションの国際化」を参照してください。
バインディングを変更するかわりに、フォーム内のUIコンポーネントがバインドされているオブジェクトを完全に変更することができます。
UIコンポーネントのリバインドの手順:
データ・コントロール・パレットから、コンポーネントの新しいバインド先となるコレクションまたは属性をドラッグし、コンポーネント上にドロップします。
または
構造ウィンドウでUIコンポーネントを右クリックし、「バインディングを編集」を選択します。バインディングを変更するUIコンポーネントに応じて、属性、表またはリストのバインディング・エディタが起動します。
ポップアップ・メニューから「既存の<コンポーネント名>のバインド」を選択します。