この章では、データ・コントロール・パレットを使用して、ADF Facesコンポーネントを使用するデータ・バインドされた表を作成する方法について説明します。
この章の内容は次のとおりです。
フォームと異なり、表を使用すると、コレクションのデータ・オブジェクトを一度に複数表示できます。図7-1に、SRDemoアプリケーションのSRListページを示します。このページでは、参照表を使用して、ログイン・ユーザーの最新のサービス・リクエストを表示しています。
コレクションを表としてドロップすると、ユーザーが特定の行を選択できるようにする選択コンポーネントを追加できます。メソッドにバインドされたコマンド・ボタンを追加すると、ユーザーはこれらのボタンをクリックして、なんらかのビジネス・ロジックを選択した行に対して実行できます。詳細は、10.3項「メソッドを実行するためのコマンド・コンポーネントの作成」を参照してください。また、必要に応じてデフォルトのコンポーネントを変更することもできます。
この章では次の内容について説明します。
基本表の作成方法
戻されたオブジェクト・セット間のナビゲーションの追加方法
作成後のデフォルトの表の変更方法
データの表示/非表示をできるようにするコンポーネントの追加方法
表の行を1行のみまたは1行以上を選択できるようにする列の挿入方法
表の現在行を手動で設定する方法
フォームを構成する個々のUIコンポーネントをコレクションの個々の属性にバインドするフォームと異なり、表では、ADF Facesのtableコンポーネントをコレクション全体にバインドするか、一度にコレクションのN個のレンジのデータ・オブジェクトにバインドします。表の個々の列は、属性にバインドされます。イテレータ・バインディングによって各オブジェクトの適切なデータが表示され、tableコンポーネントによって各オブジェクトが1行で表示されます。JDeveloperを使用すると、宣言的にこの処理を行うことができるため、コードを記述する必要がありません。
データ・コントロールを使用して表を作成するには、コレクションを戻すデータ・コントロールのメソッドにバインドする必要があります。JDeveloperでは、データ・コントロール・パレットからコレクションをドラッグ・アンド・ドロップして、宣言的にこの処理を行うことができます。
データ・バインドされた表を作成する手順:
データ・コントロール・パレットから、コレクションを戻すメソッドを選択します。
たとえば、SRList表をSRDemoアプリケーションに作成するには、findServiceRequest(Integer, String)メソッドが戻すServiceRequestsコレクションをドラッグします。このメソッドは、現行ユーザーのユーザーIDを表すIntegerパラメータ値と、openステータスを表すString値をとり、そのユーザーのオープン・リクエストをすべて戻します。図7-2に、データ・コントロール・パレットのServiceRequestsコレクションを示します。表示するレコードを決定するためのパラメータの設定方法は、10.6.1項「パラメータを取得するメソッドを使用したフォームまたは表の作成方法」を参照してください。
メソッドの戻り値をJSFページにドラッグし、ポップアップ・メニューから適切な表を選択します。
コレクションをドラッグする場合は、次の表のタイプから選択できます。
ADF表: 編集可能な表の列に表示する特定の属性と、データの表示に使用するUIコンポーネントを選択できます。デフォルトでは、コレクション・オブジェクトの各属性は、inputTextコンポーネントに表示されるため、表の編集が可能になります。
ADF読取り専用表: 「ADF表」と同じですが、各属性は、outputTextコンポーネントに表示されます。
ADF読取り専用動的表: 戻されて表示される属性が動的に決定されます。このコンポーネントは、対応するオブジェクトの属性が実行時まで不明な場合、あるいはJSFページに列名をハードコーディングしない場合に適しています。たとえば、多相コレクションを戻すメソッドがある場合(たとえば、getAnimals()は哺乳動物のコレクションまたは鳥のコレクションを戻すことができます)、動的表はそれに応じて異なる属性を表示できます。
|
注意: コレクションは、「ADFマスター表、インライン・ディテール表」としてドロップすることもできます。詳細は、8.6項「インライン表を使用したマスター表でのディテール・データの表示」を参照してください。 |
続いて表示される「表の列の編集」ダイアログから、次の操作ができます。
列の表示ラベルの変更。デフォルトでは、ラベルは表バインディングのlabelプロパティにバインドされます。このプロパティの詳細は、付録B「ADFバインディング・プロパティのリファレンス」を参照してください。このプロパティへのバインディングにより、ラベル・テキストの値を1回変更するだけで、そのラベルを表示するすべてのページに同じ内容を表示させることができます。このダイアログでは、かわりにテキストまたはEL式を入力して、ラベルの値を他の何か(リソース・ファイルのキーなど)にバインドすることができます。
たとえば、SRListページの表のステータス列のヘッダーは、status属性バインディングのlabelプロパティにバインドされています。
#{bindings.findServiceRequests1.labels.status}
しかし、次の例のように、かわりにプロパティ・ファイルのキーにバインドされるようにヘッダーを変更できます。
#{srlist['sr.status']}
この例では、srlistは、プロパティ・ファイルのロードに使用されるJSFページに定義された変数です。リソース・バンドルの使用方法の詳細は、14.4項「アプリケーションの国際化」を参照してください。
列の属性バインディングの変更。
たとえば、かわりにrequestDate属性にバインドされるようにステータス列を変更できます。次のことに注意してください。
バインディングを変更すると、列のラベルも変更されます。
別の列に現在バインドされている属性にバインディングを変更すると、UIコンポーネントはその属性に現在バインドされている列に使用されるのとは異なるコンポーネントに変更されます。
単に列を再配置する場合は、順序ボタンを使用してください。詳細は、4つ目の箇条書きを参照してください。
属性の表示に使用されるUIコンポーネントの変更。UIコンポーネントは、inputTextまたはoutputTextのいずれかで、コレクションをページにドロップする際に選択した表に基づいて設定されます。ドロップダウン・メニューを使用して別のコンポーネントに変更できます。別のコンポーネント(コマンド・リンク、コマンド・ボタンなど)を使用する場合は、このダイアログを使用してoutputTextコンポーネントを選択した後、構造ウィンドウでその別のUIコンポーネント(コマンド・リンクなど)を親としてこのコンポーネントに追加する必要があります。
順序ボタンを使用した列の順序の変更。「上」は、列を表の左1列目に移動します。「上へ」は、列を左へ1列移動します。「下へ」は、列を右へ1列移動します。「下」は、列を右端に移動します。
「新規」ボタンを使用した列の追加。このボタンを使用して列を追加すると、新しい列がダイアログの下部に追加され、デフォルトでコレクションの次の順の属性から値が移入されます。値は、編集する必要があります。選択できるのは、表がバインドされているオブジェクトに関連付けられた属性のみです。
「削除」ボタンを使用した列の削除。このボタンを使用して列を削除すると、表から列が削除されます。
「選択を有効にする」の選択による、表のselectionファセットへのtableSelectOneコンポーネントの追加。詳細は、7.6項「表での行選択の有効化」を参照してください。
「ソートの有効化」の選択によるすべての列に対するソートの有効化。
|
注意: ソートの有効化を選択した場合、表では、イテレータのrangeSize属性によって決定される、イテレータによって戻されるオブジェクト数しかソートできません。 |
データ・コントロール・パレットから表をドロップすると、テキスト・フィールドまたはフォームをドロップするのと同じ効果があります。詳細は、6.2.2項「データ・コントロール・パレットを使用してテキスト・フィールドを作成した場合の処理」を参照してください。要約すると、JDeveloperにより次の処理が行われます。
表のバインディングが作成され、そのバインディングがページ定義ファイルに追加されます。
UIコンポーネントに必要なコードがJSFページに追加されます。
データ・コントロール・パレットから表をドロップすると、表の値バインディングが作成されます。フォームで使用される属性バインディングと同様に、表の値バインディングはイテレータ・バインディングを参照します。しかし、属性ごとに異なるバインディングが作成されるのではなく、表バインディングのみが作成されます。この表バインディングは、属性ごとに子の属性名要素を保持します。例7-1に、ServiceRequestコレクションをドロップすると作成される表の表バインディングを示します。
例7-1 ページ定義ファイルにおける表の値バインディング・エントリ
<table id="findServiceRequest1" IterBinding="findServiceRequestsIter">
<AttrNames>
<Item Value="svrId"/>
<Item Value="status"/>
<Item Value="requestDate"/>
<Item Value="problemDescription"/>
<Item Value="assignedDate"/>
</AttrNames>
</table>
データにアクセスする必要があるのは表のUIコンポーネントのみであるため、表の値バインディングのみが必要です。表の列は、表バインディングからその情報を導出します。
データ・コントロール・パレットを使用してJSFページに表をドロップすると、バインド先のオブジェクトの属性ごとに1列が含まれる表が作成されます。これを実行するために、ADF Facesのtableコンポーネントが挿入されます。このコンポーネントには、表バインディングの名前付き属性ごとにADF Facesのcolumnコンポーネントが1つ含まれます。各列には、属性の値にバインドされたinputまたはoutputTextコンポーネントが含まれます。各列のヘッダー属性は、表バインディングの各属性のlabelプロパティにバインドされます。例7-2に、SRListページの表から抜粋した、単純化されたコードを示します。
例7-2 ADF Faces表のJSFコードの単純な例
<af:table var="row"
value="#{bindings.findServiceRequests1.collectionModel}
<af:column headerText="#{bindings.findServiceRequests1.labels.svrId}"
<af:outputText value="#{row.svrId}"/>
</af:column>
<af:column headerText="#{bindings.findServiceRequests1.labels.status}"
<af:outputText value="#{row.status}"/>
</af:column>
...
</af:table>
ADF Faces表自体が、イテレータ・バインディングによってアクセスされるデータに対して反復処理を実行します。これを実行するために、表はイテレータ・バインディングからの結果セットをoracle.adf.view.faces.model.CollectionModelオブジェクト内にラップします。表が反復処理を実行すると、コレクションの各アイテムは、var属性を使用してtableコンポーネント内で使用できるようになります。
先の例では、表はfindServiceRequests1表バインディングからのコレクションに対して反復処理を実行し、その結果findServiceRequestsIterイテレータ・バインディングを参照します。イテレータ・バインディングとは、現在データ・オブジェクトを決定するものです。表のvar属性をrowに設定すると、次のoutputTextタグの値に示すように、各列はrow変数を使用して、表タグに示される現在行の現在データ・オブジェクトにアクセスします。
<af:outputText value="#{row.status}"/>
表7-1に、データ・コントロール・パレットを使用して作成されるADF Faces表に対してデフォルトで定義されるその他の属性を示します。
| 属性 | 説明 | デフォルト値 |
|---|---|---|
|
|
一度に表示する行数を決定します。 |
関連付けられたイテレータ・バインディングの |
|
|
レンジの最初の行の索引(ベース0)。 |
関連付けられたイテレータ・バインディングの |
|
|
戻す行がない場合に表示するテキスト。 |
イテレータの表示可能なプロパティに評価されるEL式。表が表示できる場合に戻すオブジェクトがないときは、「まだ行がありません」と表示されます。表が表示できない場合(表に対して認可の制限が設定されている場合など)は、「アクセスは制限されました」と表示されます。 |
|
列の属性 |
||
|
|
列をソートする対象となるプロパティを決定します。 |
列の対応する属性バインディング値に設定します。 |
|
|
ソートできる列かどうかを決定します。 |
|
さらに、表の作成時に選択の有効化を選択した場合、表はselectionファセット、selection属性およびselectionListener属性も保持します。詳細は、7.6項「表での行選択の有効化」を参照してください。
組込み操作を使用してフォームと同様のナビゲーションを実行するかわりに、ADF Faces表では、tableコンポーネントに自動的に組み込まれるselectRangeChoiceBarコンポーネントを使用して組込みナビゲーションを提供します。selectRangeChoiceBarコンポーネントにより、現在のページに表示するレコードのレンジを選択するためのドロップダウン・メニューと「前へ」および「次へ」リンクがレンダリングされます。図7-3は、表におけるselectRangeChoiceBarコンポーネントの表示例を示しています。
tableコンポーネントのrows属性により、レンジ内に表示される最大行数が決定されます。次のSRList表のrows属性に対するコードSnippetが示すように、データ・コントロール・パレットを使用して表を作成する場合、デフォルトではJDeveloperでイテレータのrangeSize値と等しい行のレンジを表示するように表が設定されます。
#{bindings.findServiceRequests1.rangeSize}
rows属性は、異なるレンジ・サイズを表示するように変更できます。たとえば、イテレータが50レコードを戻すようにする一方で、表には一度に5レコードのみ表示することができます。しかし、取得数と同じレコード数を表示する場合は、表のレンジ・サイズを変更するのではなく、この属性をイテレータのレンジ・サイズにバインドしたままにし、イテレータを変更する必要があります。詳細は、6.4.2.2項「イテレータのRangeSize属性」を参照してください。
構造ウィンドウで表を選択します。
プロパティ・インスペクタで、rows属性に対し、一度に表示する行数の値を入力します。
あるいは、JSFコードにrows属性を手動で設定できます。
<af:table rows="5">
|
警告:
|
selectRangeChoiceBarコンポーネントは、コレクション内のオブジェクトの次のレンジおよび前のレンジを選択できるようにするナビゲーション・リンクを示します。コレクションの合計サイズが認識されている場合は、コレクション内の特定のレンジ・セットに直接ナビゲートできるようにするドロップダウン・メニューを示します(図7-3を参照)。イテレータのRangeSize属性を変更すると、新規レンジ・セットを表示するようにselectRangeChoiceBarコンポーネントも自動的に変更されます。
tableコンポーネントのrows属性は、first属性とともに使用してレンジを設定します。first属性は、表示する現在レンジを決定します。この属性は、リスト内の各行の索引(ベース0)です。デフォルトでは、rows属性は、関連付けられたイテレータのrangeSize属性の値にその値をバインドするEL式を使用します。first属性は、イテレータのrangeStart属性の値にその値をバインドするEL式を使用します。たとえば、SRListページの表のrows属性とfirst属性の値は、次のとおりです。
<af:table rows="#{bindings.findServiceRequests1.rangeSize}"
first="#{bindings.findServiceRequests1.rangeStart}"
各レンジは、firstによって特定された行で始まり、rows属性によって指定されるのと同じ行数のみが含まれます。
コレクションのデータ・オブジェクトの合計数がrows属性の値を超える場合、表にはselectRangeChoiceBarコンポーネントが表示され、行セット間をナビゲートできるようになります。
アクション・バインディングのロジックに依存してナビゲーションを提供するナビゲーション操作と異なり、selectRangeChoiceBarコンポーネントは、RangeChangeEventイベントを送信します。ユーザーがselectRangeChoiceBarコンポーネントによって示されるナビゲーション・リンク(「前へ」、「次へ」など)の1つを選択して別のレンジにナビゲートすると、表によってRangeChangeEventイベントが生成されます。このイベントには、現時点でレンジの一番上にあるべきオブジェクトの索引が含まれます。表は、このイベントに応じてfirst属性の値をこの新しい索引に変更します。
RangeChangeEventイベントには、リスナーが関連付けられています。表のRangeChangeListener属性は、マネージドBeanのメソッドにバインドできます。このメソッドは、RangeChangeEventイベントに応えて、つまり、ユーザーによる表のレンジの変更に応じて表がfirst属性を変更するたびに起動されます。このバインディングは、たとえば、前のレンジに対して作成されたキャッシュ済データを解放する必要がある場合など、ユーザー・ナビゲーションに応えてなんらかの補完的アクションが発生する必要がある場合に適しています。組込み操作の前後へのロジックの追加の詳細は、10.5項「宣言メソッドのオーバーライド」を参照してください。
ブラウザの「戻る」ボタンを使用すると、第6章で説明したのと同じ問題が発生することに注意してください。詳細は、6.4.4項「ブラウザの「戻る」ボタンについての考慮事項」を参照してください。イテレータは現在オブジェクトを追跡するため、ユーザーがページのナビゲーション・ボタンを使用するかわりにブラウザの「戻る」ボタンをクリックすると、イテレータが無視されるので、イテレータと表示されるページとの同期がずれてしまいます。フォームと同様に、表の場合も、ブラウザの「戻る」ボタンを使用したときにページに表示される現在行(またはレンジや複数行)は、現在の行およびレンジに関するイテレータ・バインディングの設定と一致しなくなる可能性があります。
たとえば、図7-1に示したSRListページで、IDが4のサービス・リクエストを選択した後、IDのリンク、「表示」ボタンまたは「編集」ボタンのいずれかを使用してページを移動すると、イテレータはサービス・リクエスト4を表すオブジェクトに設定されます。
6.4.4項「ブラウザの「戻る」ボタンについての考慮事項」の手順に従ってEnableTokenValidationをtrueに設定した場合、ページのトークンも4に設定されます。ブラウザの「戻る」ボタンを使用すると、何事も問題ないように見え、同じレンジが表示されます。ただし、別のボタンをクリックすると、現在行が同期していないことを示すエラーが表示されます。これは、表示されたページはトークンが0に設定された前のページであるのに、イテレータは4になっているためです。
データ・コントロール・パレットを使用して表を作成したら、属性の削除、表示順序の変更、表示に使用されるコンポーネントの変更、コンポーネントの属性バインディングの変更ができます。また、新規属性の追加も可能です。新規属性を追加する前に、表に表示する属性が表バインディングに含まれていることを確認してください。
データ・コントロール・パレットを使用して作成された表は、次のような変更ができます。
行のラベルに対するバインディングの変更
UIコンポーネントがバインドされている属性の変更
属性にバインドされているUIコンポーネントの変更
表内の列の並替え
表内の列の削除
表への列の追加
表の属性を変更する手順:
構造ウィンドウで、af:tableを右クリックし、「列の編集」を選択します。
列のラベルの変更。デフォルトでは、ラベルは表バインディングのlabelプロパティにバインドされます。このプロパティの詳細は、付録B「ADFバインディング・プロパティのリファレンス」を参照してください。このバインディングにより、ラベルを1回変更するだけで、そのラベルを表示するすべてのページに同じ内容を表示させることができます。このダイアログでは、かわりにテキストまたはEL式を入力して、ラベルの値を他の何か(リソース・ファイルのキーなど)にバインドすることができます。
たとえば、SRListページの表のステータス列のヘッダーは、status属性バインディングのlabelプロパティにバインドされています。
#{bindings.findServiceRequests1.labels.status}
しかし、次の例のように、かわりにプロパティ・ファイルのキーにバインドされるようにヘッダーを変更できます。
#{srlist['sr.status']}
この例では、srlistは、プロパティ・ファイルのロードに使用されるJSFページに定義された変数です。リソース・バンドルの使用方法の詳細は、14.4項「アプリケーションの国際化」を参照してください。
列の属性バインディングの変更。
たとえば、かわりにrequestDate属性にバインドされるようにステータス列を変更できます。次のことに注意してください。
バインディングを変更すると、列のラベルも変更されます。
別の列に現在バインドされている属性にバインディングを変更すると、UIコンポーネントはその属性に現在バインドされている列に使用されるのとは異なるコンポーネントに変更されます。
単に列を再配置する場合は、この項で後述するように、順序ボタンを使用してください。
属性の表示に使用されるUIコンポーネントの変更。UIコンポーネントは、inputTextまたはoutputTextのいずれかで、コレクションをページにドロップする際に選択したウィジェットに基づいて設定されます。ドロップダウン・メニューを使用して別のコンポーネントに変更できます。別のコンポーネント(コマンド・リンク、コマンド・ボタンなど)を使用する場合は、このダイアログを使用してoutputTextコンポーネントに変更した後、構造ウィンドウでその別のUIコンポーネント(コマンド・リンクなど)を親としてこのコンポーネントに追加する必要があります。
|
ヒント: 次のUIコンポーネントを表内で使用する際は、注意事項を考慮してください。
|
順序ボタンを使用した列の順序の変更。「上」は、列を表の左1列目に移動します。「上へ」は、列を左へ1列移動します。「下へ」は、列を右へ1列移動します。「下」は、列を右端に移動します。
「新規」ボタンを使用した列の追加。このボタンを使用して列を追加すると、新しい列がダイアログの下部に追加され、デフォルトでコレクションの次の順の属性から値が移入されます。値は、編集する必要があります。選択できるのは、表がバインドされているオブジェクトに関連付けられた属性のみです。
「削除」ボタンを使用した列の削除。このボタンを使用して列を削除すると、表から列が削除されます。
「選択を有効にする」の選択による、表のselectionファセットへのtableSelectOneコンポーネントの追加。詳細は、7.6項「表での行選択の有効化」を参照してください。
「ソートの有効化」の選択によるソート機能の追加。
|
注意: ソートの有効化を選択した場合、表では、イテレータのrangeSize属性によって決定される、イテレータによって戻されるオブジェクト数しかソートできません。 |
バインディングを変更するかわりに、表がバインドされているオブジェクトを完全に変更することができます。
表をリバインドする手順:
構造ウィンドウで表を右クリックし、「バインディングを編集」を選択して表バインディング・エディタを起動します。
エディタで、表のバインド先とする新しいコレクションを選択します。表のバインディングを変更すると、すべての列のバインディングも変更されます。7.4.1項「表示される属性の変更方法」の手順に従って、これらのバインディングを変更できます。
detailStampファセットを表内で使用すると、表示または非表示にできるデータを挿入できます。コンポーネントをこのファセットに追加すると、表には「詳細」という追加の列がトグルスイッチとともに表示されます。トグルスイッチをクリックすると、ファセットに追加されたコンポーネントが表示されます。トグルスイッチを再度クリックすると、コンポーネントは非表示になります。ファセットの概要は、6.3.2.1項「ファセットの使用方法」を参照してください。図7-4に、outputTextコンポーネントのサービス・リクエストの説明が表内でどのように非表示または表示されるかを示します(この機能は現在SRDemoアプリケーションには存在しません)。
マスター/ディテール関係がある別のオブジェクトの詳細を表示する場合(たとえば、サービス・リクエストが割り当てられているユーザーの詳細を表示する場合など)は、Master Table-Inline Detail複合コンポーネントを使用できます。マスター/ディテール関係と、マスター/ディテール複合コンポーネントの使用方法の詳細は、8.6項「インライン表を使用したマスター表でのディテール・データの表示」を参照してください。
detailStampファセットを使用するには、表示または非表示にするデータにバインドされているコンポーネントをファセットに挿入します。また、すべての詳細を一度に表示または非表示にできるようにするリンクを作成する属性を表に設定できます。
detailStampファセットを使用する手順:
ファセット内に表示する属性をデータ・コントロール・パレットからdetailStampファセット・フォルダにドラッグします。図7-5に、構造ウィンドウでのdetailStampファセット・フォルダを示します。
次に、ポップアップ・メニューから、属性を表示するUIコンポーネントを選択します。
すべての詳細を一度に非表示または表示できるようにするリンクが必要な場合は、構造ウィンドウで表を選択します。次に、プロパティ・インスペクタでallDetailsEnabled属性をtrueに設定します。
表示する属性が現在レコードに固有である場合は、表の変数を使用して現在レコードのデータを表示するように、コンポーネントを属性に単にバインドするJSFコードを置き換える必要があります。
たとえば、属性をドラッグすると、次のコードが挿入されます。
<f:facet name="detailStamp">
<af:outputText value="#{bindings.<attributename>.inputValue}"/>
</f:facet>
このコードを次のように変更する必要があります。
<f:facet name="detailStamp">
<af:outputText value="#{row.<attributename>}"/>
</f:facet>
detailStampファセット・フォルダに属性をドラッグすると、属性値バインディングがページ定義ファイルに存在しない場合は追加されます。また、ファセットのコードがJSFページに追加されます。
たとえば、SRListページで、図7-4に示すように、必要に応じてサービス・リクエストの説明を非表示にできるようにするとします。表はfindServiceRequest(Integer, String)メソッドを使用して作成されているため、構造ウィンドウでproblemDescription属性をドラッグしてdetailStampファセット・フォルダ内にドロップできます。
例7-3に、JSFページに追加されるコードを示します。
例7-3 detailStampファセットのJSFコード
<f:facet name="detailStamp">
<af:outputText value="#{bindings.problemDescription.inputValue}"
id="outputText7"/>
</f:facet>
次に、コンポーネントが表の変数を使用して各行の正しい問題の説明にアクセスするように、このコードを変更する必要があります。例7-4に、行の変数を使用した後のコードを示します。
ユーザーが行の詳細を非表示または表示にすると、表によってDisclosureEventイベント(あるいは、表のallDetailsEnabled属性がtrueに設定されている場合はDisclosureAllEventイベント)が生成されます。このイベントは、詳細を切り替える(開くまたは閉じる)ように表に指示します。
DisclosureEventイベントには、リスナーが関連付けられています。表のDisclosureListener属性は、マネージドBeanのメソッドにバインドできます。このメソッドは、DisclosureEventイベントに応えて起動され、必要な後処理を実行します。
tableSelectOneコンポーネントまたはtableSelectManyコンポーネントが表のselectionファセットに追加されると、表に「選択」列が表示されます。この列により、ユーザーは、1行のみまたは1行以上を選択し、コマンド・ボタンを通じてなんらかのアクションをそれらの行に実行できます。
tableSelectOneコンポーネントを使用すると、1行のみ選択できます。このコンポーネントは、図7-6のように、「選択」列の各行にラジオ・ボタンを示します。たとえば、SRListページの表にはtableSelectOneコンポーネントが含まれており、行を選択して「表示」または「編集」コマンド・ボタンをクリックすることで、選択したサービス・リクエストの詳細を表示または編集できます。
tableSelectManyコンポーネントは、「選択」列の各行にチェック・ボックスを示します。これにより、1つ以上の行の選択が可能になります。tableSelectManyコンポーネントを使用すると、図7-7のように、行のすべてを選択または選択解除できるテキスト・リンクも追加されます。たとえば、SRMainページの表にはtableSelectManyコンポーネントが含まれており、複数のレコードを選択してサービス履歴レコードの削除コマンド・ボタンをクリックすることで、選択したレコードを削除できます。
表の行を選択するどちらのコンポーネントにも、ユーザーへの指示となる値を保持するtext属性があります。表の行を選択するコンポーネントは、通常、選択された行に対してなんらかのアクションを実行するために使用されるコマンド・ボタンまたはコマンド・リンクを子として保持します。たとえば、SRListページの表にはコマンド・ボタンがあり、選択されたサービス・リクエストを表示または編集できます。
tableSelectOneとtableSelectManyの両コンポーネントのrequired属性は、trueに設定できます。この値に設定すると、行が選択されていない場合はエラーがスローされます。しかし、required属性を設定する場合は、必須入力エラー・メッセージを正しく表示するために、summary属性も表に設定する必要があります。required属性の詳細は、12.3.1.1.1項「検証属性の使用」を参照してください。
autoSubmit属性をtableSelectOneおよびtableSelectManyコンポーネントに設定することもできます。autoSubmit属性をtrueに設定すると、選択が行われたときに、表を保持するフォームが自動的に送信されます。詳細は、4.6項「ADF Facesのベスト・プラクティス」を参照してください。
tableSelectOneとtableSelectManyを使用するための手順はまったく異なります。ADFアプリケーションでは、操作(メソッドなど)は、イテレータの追跡対象である現在データ・オブジェクトに対して作用します。tableSelectOneコンポーネントは、選択されている現在データ・オブジェクトを表示できます。また、新たに選択された行をイテレータの現在オブジェクトに設定できます。同じイテレータが後続のページで使用される場合(たとえば、行の選択後にコマンド・ボタンをクリックしてオブジェクトを編集できるページにナビゲートする場合など)は、選択されたオブジェクトが表示されます。このように動作する理由は、イテレータとコンポーネントがシングル・オブジェクトを操作対象とするためです。異なるバインディング・コンテナの異なるイテレータ・バインディングが同じ行セット・イテレータにバインドされるため、現在行の設定は同じになります。
しかし、tableSelectManyコンポーネントでは、選択されたオブジェクトが複数存在します。ADFモデル・レイヤーには、「現在」とは対照的な「選択」という概念はありません。操作をオブジェクトに対して実行できるように、選択された各オブジェクトをループして、順に現在オブジェクトにするロジックをモデル・レイヤーに追加する必要があります。
selectionファセットのコンポーネントを使用して現在オブジェクトを設定し、次のページへナビゲートするためのcommandButtonを提供するかわりに、リンクをクリックして選択に対して操作を実行し、かつ別のページにナビゲートできるようにするcommandLinkコンポーネントを使用すると、最初に行を選択し、次にコマンド・ボタンをクリックしてアクションを実行してナビゲートする必要がある手順を省略できます。しかし、現在オブジェクトをイテレータ・バインディングに手動で設定する必要があります。現在オブジェクトの手動設定の詳細は、7.7項「コマンド・コンポーネントを使用した現在オブジェクトの設定」を参照してください。
|
ヒント: 後続のページで同じイテレータを使用しない場合は、通常、選択された行を表すパラメータを後続のページ用に手動で設定する必要があります。たとえば、SRDemoアプリケーションのSREditページのフォームは、findServiceRequestById(Integer)メソッドを使用して作成されています。フォームを正しく表示するためには、選択された行のIDを表すIntegerをそのメソッドに渡す必要があります。パラメータが設定されないと、フォームにはイテレータ内の最初の行が表示されます。詳細は、10.4項「コマンド・コンポーネントを使用したパラメータ値の設定」を参照してください。 |
コレクションを表としてデータ・コントロール・パレットからドロップする際に、selectionファセットの挿入を選択できます。「選択を有効にする」を選択すると、tableSelectOneコンポーネントが、tableSelectOneの子となる「発行」commandButtonコンポーネントとともにselectionファセットに挿入されます。
|
注意: データ・コントロール・パレットを使用して表を作成する場合、tableSelectManyコンポーネントは挿入できません。このコンポーネントは、表の作成後に手動で追加する必要があります。ただし、ADFアプリケーションで複数選択処理を使用するには、追加コードを作成する必要があります。詳細は、7.6.4項「selectionファセットにおけるtableSelectManyコンポーネントの使用方法」を参照してください。 |
「発行」ボタンをメソッドにバインドする場合は、commandButtonコンポーネントを任意のメソッドまたは操作にリバインドする必要があります。リバインドの手順は、13.6項「アクションへのADFバインディングの追加」を参照してください。
また、tableSelectOneコンポーネントをselectionファセットに手動で追加できます。
selectionファセットを手動で使用する手順:
構造ウィンドウで、af:tableを選択し、ポップアップ・メニューから「列の編集」を選択します。
「表の列の編集」ダイアログで、「選択を有効にする」を選択し、「OK」をクリックします。
tableSelectOneコンポーネントが(tableコンポーネントの選択と連携して機能する必須リスナーおよび属性とともに)selectionファセット・フォルダに追加されます。
構造ウィンドウで、表のselectionファセット・フォルダを開き、af:tableSelectOneを選択します。
新しいコンポーネントのプロパティ・インスペクタで、選択の処理に使用されるコマンド・ボタンまたはコマンド・リンクの使用に関する指示を示すtext属性の値を入力します。
(オプション): 「発行」コマンド・ボタンをデータ・コントロール・パレットから選択したメソッドまたは操作にリバインドします。リバインドの手順は、13.6項「アクションへのADFバインディングの追加」を参照してください。メソッドを使用したコマンド・ボタンの作成の詳細は、10.3項「メソッドを実行するためのコマンド・コンポーネントの作成」を参照してください。
|
注意: コマンド・コンポーネントをファセットに追加しないかぎり、text属性の値は表示されません。 |
例7-5に示すように、表の初回作成時(またはその後の編集時)に選択を有効化すると、text属性の値としてSelect andが設定されたtableSelectOneコンポーネントがselectionファセットに挿入されます。「発行」コマンド・ボタンも子として挿入されます。
例7-5 selectionファセットのコード
<f:facet name="selection">
<af:tableSelectOne text="Select and">
<af:commandButton text="Submit"/>
</af:tableSelectOne>
例7-6に示すように、表のselectionState属性の値は、イテレータから作成されたコレクション・モデルの選択された行に評価されるEL式です。selectionListener属性の値は、コレクション・モデルのmakeCurrentメソッドに評価されます。この値は、コンポーネントが選択された行を現在オブジェクトとしてイテレータに設定できるようにするものです。
例7-6 表のselection属性
<af:table rows="#{bindings.findServiceRequests1.rangeSize}"
first="#{bindings.findServiceRequests1.rangeStart}"
var="row"
selectionState="#{bindings.findServiceRequests1.collectionModel.selectedRow}"
selectionListener="#{bindings.findServiceRequests1.collectionModel.makeCurrent}"
id="table2">
ユーザーが選択を行い、関連付けられたコマンド・ボタンをクリックすると、tableSelectOneコンポーネントにより、表のgetSelectionState()メソッドをコールして取得されたRowKeySetが更新されます。選択の状態はコレクション・モデルの選択された行に評価されるため、その行は選択済としてマークされます。この選択は、コマンド・ボタンに関連付けられたActionListenerをコールする前に実行されます。
tableSelectOneコンポーネントの場合、ActionListenerの起動前に現在行が選択されるため、コマンド・ボタンのActionListenerを、行のデータに対して該当する処理を実行するマネージドBeanのメソッドにバインドできます。あるいは、単にロジックを宣言メソッドに追加できます。詳細は、10.5項「宣言メソッドのオーバーライド」を参照してください。
tableSelectOneコンポーネントは、表の選択の状態が変更されると、SelectionEventイベントをトリガーします。SelectionEventは、選択された行と選択解除された行をレポートします。SelectionListener属性はコレクション・モデルのmakeCurrentメソッドにバインドされているため、イベントが発生するとこのメソッドが起動し、イテレータに新しい現在行を設定します。
ADF表バインディングを使用する表にtableSelectManyコンポーネントを追加する場合は、操作をオブジェクトに対して実行できるように、選択された各行を順に現在オブジェクトに設定するコードも追加する必要があります。
ADFアプリケーションでtableSelectManyコンポーネントを使用する手順:
7.2.1項「基本表の作成方法」に示すように表を作成します。ただし、「選択を有効にする」は選択しないでください。
構造ウィンドウで、Table facetsフォルダを開き、selectionファセット・フォルダを右クリックして、「selectionの中に挿入」→「TableSelectMany」の順に選択します。
構造ウィンドウでaf:tableノードを選択し、プロパティ・インスペクタでSelectionStateおよびSelectionListener属性の値を必要に応じて削除します。そうすることで、コンポーネントが選択された行の1つを現在オブジェクトに設定することを防ぎます。このロジックは、作成するコードによって処理する必要があるためです。
データ・コントロール・パレットから、選択されたオブジェクトに対して作用するメソッドをaf:tableSelectManyノードの上にドラッグします。次に、ポップアップ・メニューから、「メソッド」→「コマンド・ボタン」の順に選択します。そうすることで、メソッドがコマンドボタンとしてドロップされます。この時点で、メソッドのパラメータ値を(必要に応じて)設定します。手順は、10.3.1項「サービス・メソッドにバインドされたコマンド・コンポーネントの作成方法」を参照してください。
たとえば、SRDemoアプリケーションで作業している場合に、ユーザーが選択した行を削除できるようにするには、removeEntity(Object)メソッドをaf:tableSelectManyノードにドラッグします。
また、この時点で、各行を順に現在行にしてメソッドが一連の行に対して作用するようにするロジックをメソッドに追加する必要があります。ロジックを追加するには、コマンド・ボタンのドロップ時に作成される宣言メソッドをオーバーライドする必要があります。手順は、10.5項「宣言メソッドのオーバーライド」を参照してください。
このコードにより、removeEntity(Object)メソッドをオーバーライドして必要なロジックを追加できます。
次の処理を実行するロジックを宣言メソッドに追加します。
表コンポーネントにアクセスします。
すべての選択された行のリストを取得します。
オブジェクトを順に取得し、元のメソッドをそれぞれに対して実行します。これを実行するには、次のように、ロジックが選択された行のリストをループする必要があります。
ループで行を取得します。
その行のキーを取得します。
その行を現在オブジェクトとしてADFバインディングに設定します。
宣言メソッドをコールしてオブジェクトを削除します。
完了したら、正しいオブジェクトのセットが表示されるように、イテレータをリフレッシュするロジックを追加する必要があります。コードの例は、例7-10を参照してください。
tableSelectManyコンポーネントを表に挿入して、サービス・メソッドにバインドされたコマンド・ボタンを追加すると、次の処理が実行されます。
tableSelectManyおよびcommandButtonコンポーネントがtableコンポーネントのselectionファセットに追加されます。
ページ定義ファイルでバインドされたメソッドに対してメソッド・バインディングが作成され、メソッドをボタンとしてドロップしたときに決定される、メソッドに必要なパラメータ(存在する場合)の値を保持するNamedData要素が挿入されます。
次に、メソッドをオーバーライドし、表の選択された各行にアクセスして現在行となった行にメソッドを実行するロジックを追加する必要があります。
たとえば、findAllProduct()メソッドを使用して、すべての製品を表示する表を作成するとします。次に、ユーザーがremoveEntity(Object)メソッドを使用して削除する製品を選択できるように、tableSelectManyコンポーネントを追加します。例7-7に、JSFページのコードを示します。
例7-7 tableSelectManyコンポーネントを使用する表のJSFコード
<af:table value="#{bindings.findAllProducts1.collectionModel}"
var="row" rows="#{bindings.findAllProducts1.rangeSize}"
first="#{bindings.findAllProducts1.rangeStart}"
id="table1">
<af:column>
...
</af:column>
<f:facet name="selection">
<af:tableSelectMany text="Select items and ..."
id="tableSelectMany1">
<af:commandButton text="removeEntity"
disabled="#{!bindings.removeEntity.enabled}"
id="commandButton1"
action="#{backing_MultiDelete.commandButton1_action}"/>
</af:tableSelectMany>
</f:facet>
</af:table>
例7-8に示すように、removeEntity(Object)メソッドのオブジェクトのパラメータ値を表の現在行にバインドするコードがページ定義に追加されます。
例7-8 表バインディングにおけるパラメータが現在行のメソッドに対するメソッド・アクション・バインディング
<methodAction id="removeEntity" InstanceName="SRPublicFacade.dataProvider"
DataControl="SRPublicFacade" MethodName="removeEntity"
RequiresUpdateModel="true" Action="999">
<NamedData NDName="entity"
NDValue="${bindings.findAllProducts1.currentRow.dataProvider}"
NDType="java.lang.Object"/>
</methodAction>
<table id="findAllProducts1" IterBinding="findAllProductsIter">
<AttrNames>
...
</AttrNames>
</table>
ロジックを宣言メソッドに追加するためにビジュアル・エディタでボタンをダブルクリックすると、メソッド・ロジックにアクセスできるコードが関連付けられたバッキングBeanに追加されます。
たとえば、removeEntity(Object)メソッドをSRDemoアプリケーションからファセットにドロップした場合は、ビジュアル・エディタでremoveEntityボタンをダブルクリックすると、例7-9に示すコードが関連付けられたバッキングBeanに追加されます。
例7-9 バッキングBeanにおける宣言メソッドのコード
public String commandButton1_action() {
BindingContainer bindings = getBindings();
OperationBinding operationBinding =
bindings.getOperationBinding("removeEntity");
Object result = operationBinding.execute();
if (!operationBinding.getErrors().isEmpty())
return null;
return null;
}
次に、生成されたコードの前に選択された各行にアクセスするコードを追加します。生成されたコードを使用して、その行のオブジェクトに対してメソッドを実行します。次に、生成されたコードの後に、問合せを再実行してページをリフレッシュするコードを追加します。
たとえば、ユーザーが製品を選択してremoveEntity(Object)メソッドにバインドされたコマンド・ボタンを使用して削除することにより、製品の行を削除できるようにするとします。ボタンをダブルクリックして、宣言コードをバッキングBeanに追加します。次に、例7-10の太字で示されたコードを追加してオブジェクトを削除します。太字ではないコードは、例7-9に示したJDeveloperによって生成されたコードです。
例7-10 tableSelectManyを使用可能にする完成したバッキングBeanのコード
public String commandButton1_action() {
//Access the tableSelectMany1 table. Note that the table name
//is taken from the id of the table in the JSF page.
CoreTable table = this.getTable1();
//Obtain a list of all selected rows from the table
Set rowSet = table.getSelectionState().getKeySet();
Iterator rowSetIter = rowSet.iterator();
//Use the declarative method to get the ADF bindings
BindingContainer bindings = getBindings();
//Get the object to delete. To do this, you must get the
//iterator binding for the Products in the page definition file,
//and cast it to DCIteratorBinding for further processing
DCIteratorBinding pr_dcib = (DCIteratorBinding)
bindings.get ("findAllProductsIter");
//Loop through the set of selected row numbers and delete the
//equivalent object from the Products collection.
while (rowSetIter.hasNext()){
//get the table row
Key key = (Key) rowSetIter.next();
//set the current row in the ADF binding to the same row
pr_dcib.setCurrentRowWithKey(key.toStringFormat(true));
//Obtain the Products object to delete
RowImpl prRow = (RowImpl) pr_dcib.getCurrentRow();
//Delete the object by first accessing the data and then
//using the generated code to execute the declarative method
Products prObjectToDelete = (Products) prRow.getDataProvider();
OperationBinding operationBinding =
bindings.getOperationBinding("removeEntity");
//You don't need to set the parameter, as this was done
//declaritively when you dropped the button on the page
Object result = operationBinding.execute();
if (!operationBinding.getErrors().isEmpty())
return null;
}
//Re-execute the query to refresh the screen
OperationBinding requery = bindings.getOperationBinding("findAllProducts");
requery.execute();
//Stay on the same page, so no returned outcome needed
return ];
}
ユーザーが複数の行を選択してコマンド・ボタンをクリックすると、アプリケーションは、表にアクセスして選択された各行を特定し、それらの行について行セットを作成します。次に、バインディング・コンテナにアクセスし、そのコンテナからコレクション全体の管理に使用されるイテレータにアクセスして、選択された行の行セットを管理できる汎用のイテレータ・バインディングにキャストします。
このイテレータは、各行について次の処理を実行します。
キーを設定します。
表6-1「組込みナビゲーション操作」で説明しているように、そのキーを使用してsetCurrentRowWithKey操作を使用し、行をイテレータの現在行に設定します。
その現在行を使用して、メソッドの実行対象となるオブジェクトを作成します。
そのオブジェクトの関連データにアクセスします。
メソッドを実行します。
完了して行セットに行がないと、アプリケーションはバインディング・コンテナのイテレータにアクセスし、問合せを再実行して表に表示される行のセットをリフレッシュします。
オブジェクトの現在行をプログラムでイテレータに設定する必要がある場合があります。たとえば、SRDemoアプリケーションのSRListページでは、図7-8に示すように2番目の列でコマンド・リンクを使用しています。ユーザーはこのリンクをクリックすると、先に行を選択しなくても、サービス・リクエストを直接編集できます。
コマンド・リンクを使用するとユーザーの手順を省略できますが、コマンド・リンクはselectionファセットと同じ機能を提供するわけではなく、現在行を特定したり、イテレータに現在行を設定することができません。そのため、手動で現在行を設定する必要があります。
組込み操作のsetCurrentRowWithKeyまたはsetCurrentRowWithKeyValueを使用して現在行を設定します。これらの操作は、コレクションに対するイテレータの組込みメソッドです。setCurrentRowWithKey操作を使用すると、文字列化されたキーを指定して現在行を設定できます。setCurrentRowWithKeyValue操作を使用すると、主キーの値を指定して現在行を設定できます。現在行の操作の詳細は、setCurrentRowWithKeyとsetCurrentRowWithKeyValueの相違点の理解に関する項を参照してください。
これらの操作は任意のタイプのコマンド・コンポーネントとしてドロップできますが、このような状況では通常、commandLinkコンポーネントが使用されます。次の手順では、このコンポーネントをsetCurrentRowWithKey操作およびsetCurrentRowWithKeyValue操作とともに使用する方法について説明します。
データ・コントロール・パレットから、setCurrentRowWithKey操作またはsetCurrentRowWithKeyValue操作をドラッグします。
ポップアップ・メニューから、「操作」→「ADFコマンド・リンク」の順に選択します。
アクション・バインディング・エディタで、rowKeyパラメータの値を設定する必要があります。デフォルトでは、${bindings.setCurrentRowWithKey_rowKey}に設定されます。実際の値は、現在行の特定に使用できるものにする必要があります。
たとえば、図7-8のコマンド・リンクには、現在行をクリックされるリンクと同じ行に設定する必要があります。setCurrentRowWithKey操作の場合、行の文字列化されたキーにアクセスするために、バインディングのrowKeyStrプロパティまたは#{row.rowKeyStr}を使用できます。
あるいは、setCurrentRowWithKeyValue操作を使用する場合は、rowKeyを現在行の値または#{row.svrId}に設定できます。
表の現在行の設定に使用される変数(この場合はrow)の詳細は、7.2.2.2項「ADF Faces表のJSFページのコード」を参照してください。
setCurrentRowWithKey操作をコマンド・コンポーネントとして使用すると、その操作に対してアクション・バインディングが作成されます。この操作は、現在行を特定するパラメータ(rowKey)をとるため、その値の設定に使用されるNamedData要素を保持します(パラメータおよびNamedData要素の詳細は、10.3項「メソッドを実行するためのコマンド・コンポーネントの作成」を参照してください)。
例7-11に、setCurrentRowWithKey操作をドロップして#{row.svrId}をrowKeyパラメータの値として設定したときに作成されるページ定義ファイルのコードを示します。
例7-11 setCurrentRowWithKey操作のページ定義コード
<action id="setCurrentRowWithKey" IterBinding="findServiceRequestsIter"
InstanceName="SRPublicFacade.dataProvider"
DataControl="SRPublicFacade" RequiresUpdateModel="false"
Action="96">
<NamedData NDName="rowKey" NDValue="${row.rowKeyStr}"
NDType="java.lang.String"/>
</action>
ユーザーがコマンド・リンクをクリックすると、現在行を特定するrowKeyパラメータを使用して、setCurrentRowWithKey操作がイテレータで実行されます。tableSelectOneコンポーネントと同様に、同じイテレータを使用して現在レコードを表示すると、正しいデータが表示されます。
|
ヒント: SRDemoアプリケーションのものと同様の機能の場合、現在行を表すパラメータ値を渡すコマンド・リンクが必要になることがあります。この値は、次のフォームの作成に使用されるメソッドで使用されます。詳細と手順は、10.4項「コマンド・コンポーネントを使用したパラメータ値の設定」を参照してください。 |