標準リストコントローラーの使用
学習の目的
この単元を完了すると、次のことができるようになります。
- Visualforce 標準リストコントローラーとは何か、標準 (レコード) コントローラーとの違いは何かを説明する。
- 標準リストコントローラーで提供される、標準コントローラーとは異なるアクションを 3 つ挙げる。
- Visualforce ページで標準リストコントローラーを使用して、レコードのリストを表示する。
- ページネーションを定義して Visualforce ページに追加する。
標準リストコントローラーの概要
標準リストコントローラーを使用すると、レコードセットの表示や操作が行える Visualforce ページを作成できます。
レコードのリストの表示は、ほぼすべての Web アプリケーションの基本動作です。Visualforce では、バックエンドコードなしでマークアップのみを使用して、同じタイプのレコードのリストを非常に簡単に表示できます。この秘密の鍵は標準コントローラーにあり、この場合は標準<>リスト>コントローラーが使用されます。
標準リストコントローラーには、特定のオブジェクトレコードのクエリ、コレクション変数でのレコードの使用、結果の絞り込みやページネーションなど、多数の強力な自動動作があります。ページへの標準リストコントローラーの追加は標準 (レコード) コントローラーの追加と非常に似ていますが、一度に 1 レコードを操作する代わりに、一度に多数のレコードを操作することを目的としています。
レコードのリストを表示する
<>> などの標準リストコントローラーと反復コンポーネントを使用して、レコードのリストを表示します。
標準 (レコード) コントローラーにより、Visualforce ページで使用できる変数に 1 つのレコードを簡単に読み込むことができます。標準<>リスト>コントローラーも同様ですが、1 つのレコードの代わりに、レコードのリストまたはコレクションを変数に読み込みます。
個々のレコードではなくコレクションを操作するため、反復コンポーネントを使用してレコードを表示する必要があります。反復コンポーネントは、1 つの値ではなく類似した項目のコレクションと連動します。反復コンポーネントはそのコレクションをループし、各レコードに対して、コンポーネントマークアップの一部として提供するテンプレートに基づいて出力を生成します。これは複雑に思えるかもしれませんが、マークアップを読めばすぐに理解できます。
標準リストコントローラーを使用するためのマークアップは、一度に 1 レコードの標準コントローラーを使用するためのマークアップとほぼ同じです。
- 新しい Visualforce ページを作成するには、開発者コンソールを開き、<>[File (ファイル)]> | <>[New (新規)]> | <>[Visualforce Page (Visualforce ページ)]> をクリックします。ページ名に <><
>ContactList>> と入力します。 - エディターで、任意のマークアップを次のように置き換えます。
<apex:page standardController="Contact" recordSetVar="contacts"> <apex:pageBlock title="Contacts List"> <!-- Contacts List --> <apex:pageBlockTable value="{! contacts }" var="ct"> <apex:column value="{! ct.FirstName }"/> <apex:column value="{! ct.LastName }"/> <apex:column value="{! ct.Email }"/> <apex:column value="{! ct.Account.Name }"/> </apex:pageBlockTable> </apex:pageBlock> </apex:page> - <>[Preview (プレビュー)]> をクリックして、変更処理中に確認できるページのプレビューを開きます。標準の Salesforce ページヘッダー、サイドバー要素、取引先責任者のリストが表示された新規ウィンドウが開きます。

標準リストコントローラーの使用方法は、標準コントローラーの使用方法によく似ています。最初に <>> コンポーネントの <>standardController> 属性を設定し、次に同じコンポーネントの <>recordSetVar> 属性を設定します。<>standardController> 属性では、標準コントローラーと同様に、作業するオブジェクトを設定します。recordSetVar では、レコードのコレクションで作成される変数の名前 (ここでは <>{! contacts }>) を設定します。命名規則に従って、通常この変数には複数形のオブジェクト名が付けられます。
<>> は、プラットフォームのスタイル設定が適用されたデータテーブルを生成する反復コンポーネントです。テーブルマークアップでの処理を次に示します。
- <><
>>> の value 属性は、標準リストコントローラー <><>{! contacts }>> で読み込まれた変数に設定されます。これは <><>>> で操作するレコードのリストです。 - そのリストの各レコードに対して 1 レコードずつ、<><
>>> はレコードを <><>>> の var 属性で指定された変数に割り当てます。この場合、変数には <><>ct>> が指定されます。 - 各レコードに対して、<><
>>> は <><>>> 本体内の一連の <><>>> コンポーネントで定義された行を使用して、テーブルに新しい行を作成します。<><>>> コンポーネントは、現在のレコードを表す <><>ct>> 変数を使用して、そのレコードの項目値を順に取得します。 - ループの外側で、<><
>>> は <><>>> コンポーネントの項目を使用して、各項目の表示ラベルを調べることで列ヘッダーを作成します。
これは非常に複雑で、最初は反復コンポーネントを理解することは難しいかもしれません。この時点でできることは、自分自身で作成してみることです。テーブルに表示する項目を選択します。<>> と <>> の別の属性を調べて、慣れるまで試してみてください。また、<>> や <>> など、その他いくつかの反復コンポーネントも使用してみてください。
リストにリストビューの検索条件を追加する
<>{! listViewOptions }> を使用して、オブジェクトで使用可能なリストビュー検索条件のリストを取得します。<>{! filterId }> を使用して、標準リストコントローラーの結果に使用するリストビュー検索条件を設定します。
標準リストコントローラーには、リストの表示を変更できる多数の機能があります。最も強力な機能の 1 つに、リストビュー検索条件があります。リストビュー検索条件は、コードを使用せずにクリックで宣言的に作成します。標準リストコントローラーでは、ページで定義済みのリストビュー検索条件を使用できます。
- <><
>>> 全体を <><>>> タグでラップします。標準リストコントローラーのリストビュー検索条件を変更するには、新しい値をサーバーに送信する必要があります。この送信を実行する一般的な方法は、<><>>> コンポーネントで作成されたフォームを使用することです。 - <><
>>> タグで、次の属性を追加します。
id="contacts_list"
Ajax 効果 (これについては後ほど説明します) に使用できる「名前」が <>> に付けられます。
- <><
>>> 開始タグの後、<><>>> の上に、次のマークアップを追加します。ページの完全なコードは次のようになります。Filter: <apex:selectList value="{! filterId }" size="1"> <apex:selectOptions value="{! listViewOptions }"/> <apex:actionSupport event="onchange" reRender="contacts_list"/> </apex:selectList>A new filter control appears above the list.<apex:page standardController="Contact" recordSetVar="contacts"> <apex:form> <apex:pageBlock title="Contacts List" id="contacts_list"> Filter: <apex:selectList value="{! filterId }" size="1"> <apex:selectOptions value="{! listViewOptions }"/> <apex:actionSupport event="onchange" reRender="contacts_list"/> </apex:selectList> <!-- Contacts List --> <apex:pageBlockTable value="{! contacts }" var="ct"> <apex:column value="{! ct.FirstName }"/> <apex:column value="{! ct.LastName }"/> <apex:column value="{! ct.Email }"/> <apex:column value="{! ct.Account.Name }"/> </apex:pageBlockTable> </apex:pageBlock> </apex:form> </apex:page>
- メニューから異なる検索条件を選択します。取引先責任者リストはどのように変化するでしょうか。
ここで作成した [検索条件] メニューから新しいオプションを選択すると、2 つの変化があります。まず、新しい検索条件を選択したときにレコードのリストが変更されます。(いくつかの異なるオプションの選択が必要な場合があります。標準の DE 組織のサンプルデータを使用している場合、複数のリストビューで同じレコードが表示されます)。
次に、あまり目立ちませんが、<>ページ全体は再読み込みされることなく>、リストが更新されます。この「Ajax」効果は、<>> コンポーネントの <>reRender="contacts_list"> 属性で適用されます。コンポーネントと reRender の複合効果によって、reRender 属性で指定されたページの一部のみが更新されます。<>> に <>id="contacts_list"> を追加しているため、アクションの完了時に、ページ全体が再読み込みされることなく <>> のみが更新されます。
このページでのこの新機能の完全なライフサイクルは、次のようになります。
- ページが読み込まれると、<><
>{! listViewOptions }>> 式からリストを取得することで、使用可能な検索条件のメニューが <><>>> で作成されます。<><>listViewOptions>> は、標準リストコントローラーで提供されるプロパティです。 - メニューから新しいオプションを選択すると、<><
>>> コンポーネントによって <><>onchange>> イベントが起動されます。 - <><
>onchange>> が起動すると、<><>filterId>> プロパティに新しい項目を送信することで、新しく選択されたリストビューがページから戻され、<><>>> に設定されます。 - プロパティが更新されると、contacts 変数の新しい該当レコードのコレクションを含む、サーバーからの新しい応答をページが受信します。
- ただし、<><
>>> ではページの一部のみの表示が指定されているため、ページ全体が再読み込みされる代わりに、Ajax (非同期 JavaScript) を使用してページが更新されます。
正味の効果は、複雑で高度な動作をほんの数行のマークアップの追加で実現できることにあります。
ページネーションをリストに追加する
標準リストコントローラーのページネーション機能を使用すると、ユーザーは長いリストのレコードを 1 「ページ」ずつ表示できます。
これまで開発してきた機能は、Developer Edition 組織のサンプルデータとして提供されている短いリストのレコードでは快適に動作します。ただし、数百や数千、または数百万件のレコードがある実際の組織ではどうでしょうか。すべてのレコードを 1 ページに表示した場合は、うまく機能しません。
実際、デフォルトでは、標準リストコントローラーは検索条件に一致する最初の 20 件 (存在する場合) のレコードのみを表示します。この 20 件以外のレコードにユーザーがアクセスできるようにしたり、1 ページに 20 件を超えるレコードを表示したりするにはどうすればよいでしょうか。
答えはページネーションにあります。ページネーションは標準の Web アプリケーションユーザーインターフェースです。長いリストのレコードを 1 「ページ」ずつ、通常は <>[Next (次へ)]> と <>[前へ]> リンクを使用して前後に移動できます。標準リストコントローラーや進行状況インジケーター、メニューなどのツールを使用してページにページネーションを追加し、ページあたりのレコード数を変更できます。
- 取引先責任者リスト <><
>>> の下に、次のマークアップを追加します。
<!-- Pagination -->
<table style="width: 100%">
<tr>
<td>
<!-- Page X of Y -->
</td>
<td align="center">
<!-- Previous page -->
<!-- Next page -->
</td>
<td align="right">
<!-- Records per page -->
</td>
</tr>
</table>追加する 3 つのページネーションコントロールを含めることができる HTML テーブルが作成されます。
- <><
>>> コメント行を次のマークアップで置き換えます。
Page: <apex:outputText value=" {!PageNumber} of {! CEILING(ResultSize / PageSize) }"/>ユーザーが表示しているページと残りのページ数を示す、進行状況インジケーターがリストに追加されます。DE 組織で試行している場合は、「Page 1 of 1」 (1/1 ページ) と表示されます。
- Replace the
<!-- Previous page -->and<!-- Next page -->comment lines with the following markup.This markup provides Previous and Next links on the page. The markup covers two possibilities: when there are more records to view in a given direction, then the link is active; and when there aren’t more pages in a given direction, the link is disabled.<!-- Previous page --> <!-- active --> <apex:commandLink action="{! Previous }" value="« Previous" rendered="{! HasPrevious }"/> <!-- inactive (no earlier pages) --> <apex:outputText style="color: #ccc;" value="« Previous" rendered="{! NOT(HasPrevious) }"/> <!-- Next page --> <!-- active --> <apex:commandLink action="{! Next }" value="Next »" rendered="{! HasNext }"/> <!-- inactive (no more pages) --> <apex:outputText style="color: #ccc;" value="Next »" rendered="{! NOT(HasNext) }"/>
- Replace the
<!-- Records per page -->comment line with the following markup.This markup provides a menu for changing the number of records per page. Here we’ve only added an option to display fewer records on a page. Select “5” from the list, and see what happens to the list, and the other controls.Records per page: <apex:selectList value="{! PageSize }" size="1"> <apex:selectOption itemValue="5" itemLabel="5"/> <apex:selectOption itemValue="20" itemLabel="20"/> <apex:actionSupport event="onchange" reRender="contacts_list"/> </apex:selectList>
標準リストコントローラーで提供される多数の機能が含まれたリストページが表示されます。
<img alt="Contacts list with pagination controls" class="image" src="images/kix.d9v8yz1afesw.jpg" width="672.0"/>
進行状況インジケーターでは、何ページあるかを示すために <>PageNumber>、<>ResultSize>、<>PageSize> の 3 つのプロパティが使用されています。最後の 2 つは、最も近い整数に四捨五入する数式で使用されます。これにより、インジケーターに「Page 2 of 1.6」 (2/1.6 ページ) などの不適切な値が表示されることを防ぎます。
ページネーションコントロールの <>> コンポーネントは、標準リストコントローラー <>Previous> と <>Next> で提供される 2 つのアクションメソッドを参照します。その結果、<>Previous> または <>Next> アクションを実行するリンクが表示されます。
では、<>{! HasPrevious }> などの式が含まれる rendered 属性は何を意味するのでしょうか。Visualforce はこの属性によって、コンポーネントを条件付きで (Boolean 式の結果に応じて) 表示できるようにします。ここでは、ページマークアップは標準リストコントローラー <>HasPrevious> と <>HasNext> で提供される Boolean プロパティを参照しています。これらのコントローラーは、指定方向にさらにレコードがあるかどうかを示します。rendered 属性でこの式を使用することで、そのコンポーネントの結果をページに表示または非表示にすることができます。これにより、ページを最初に読み込んだときは <>[前へ]> リンクがグレー表示になり、<>[Next (次へ)]> リンクをクリックして先に進むと有効になります。
ページあたりのレコード数選択メニューでは、以前に使用した <>> を使用しますが、メニューの値を取得するコントローラーメソッドをコールする代わりに、目的の値の <>> 要素を使用します。ここでも、<>> タグは選択値が変更された場合にメニューのアクションを実行し、<>reRender="contacts_list"> を使用して <>> のみを更新します。ここで異なる点は、<>> で標準リストコントローラーの <>PageSize> プロパティを設定していることです。
もうひとこと...
標準リストコントローラーには Web アプリケーションで一般的な多数の機能があり、ここで紹介している機能はほんの一部にすぎません。
たとえば、1 ページごとに前後に移動する <>Previous> アクションと <>Next> アクションに加えて、レコードのリストの先頭または最後に移動する <>First> アクションや <>Last> アクションもあります。
マークアップで操作する標準リストコントローラーは、<>StandardSetController> Apex クラスに基づいています。このクラスの詳細とすべての機能については、<>『Apex リファレンスガイド』>を参照してください。
ここで作成した例では、並び替えの問題があります。通常はリストのデフォルトの並び替え順を設定し、並び替え順をその場で変更できる列ヘッダーを含めることが望まれます。実際には、Visualforce 単独で並び替え順を変更することはできません。並び替えとクリック可能な列ヘッダーをサポートするために必要な追加の Visualforce マークアップと Apex コードの量はそれほど多くありませんが、カスタムコードが必要になります。その開始点については、その他のリソースを参照してください。
リソース
- <>Visualforce 開発者ガイド>: <>Standard Controllers (標準コントローラー)><>>
- <>Visualforce 開発者ガイド>: <>Standard List Controllers (標準リストコントローラー)>
- <>Visualforce 開発者ガイド: ><>Create a Custom List View in Salesforce Classic (Salesforce Classic のカスタムリストビューの作成)><>>
- <>Visualforce 開発者ガイド>: <>apex:outputLink コンポーネント><>>
- <>Visualforce 開発者ガイド>:<><> >><>apex:repeat コンポーネント><>>
- <>Apex リファレンスガイド>: <>StandardController クラス>
- <>Apex リファレンスガイド>: <>StandardSetController クラス><>>
- <>Salesforce 開発者ブログ: ><>Twitter Bootstrap and Visualforce in Minutes (Twitter Bootstrap を使用して Visualforce ページを数分で作成)><>>
