Salesforce の pageBlockTable のヘッダー行クリックでソートする方法

仕事で Salesforce を使ったシステムを開発していて
「一つの画面に複数の表を表示する」
という機能の実装時にハマったのでメモ。

ちなみに、以下は作りたかったの画面の例。
(一日の気温を、一時間毎の表・一日の平均の2つ表示してみたい)


2つの表は pageBlockTable でよいのだけれど、問題はソート機能。
Salesforce のオブジェクトのビューでは、表のヘッダー行クリックでソートができる。
ただし pageBlockTable を使った表には、その機能はない。
(同じことをやろうとすると、ソート機能を実装し直さなければいけないっぽい)

簡単に同様のことをやれないか、ググッてみると以下の記事を発見!!
要は、DataTables という jQuery のプラグインが良さげらしい。

Client-side sorting and pagination of an apex:pageBlockTable

これを基に、冒頭の例の画面を作ってみよう。
まずは、気温オブジェクトを作る。

テストデータは、気象庁のページを元に、手入力でポチポチ入れる。

次に、DataTables の Getting started を参考に、Visualforce page, component, Apex を作成。
(VF page は VF component を呼び出すのみ)
<apex:component controller="TemperatureController">
<apex:pageBlock ><h1>一時間毎の気温</h1>
<apex:pageBlockSection columns="1">
<apex:pageBlockTable value="{!tempera_list_by_time}" var="t" styleClass="dataTable">
<apex:column value="{!t.City__c}"/>
<apex:column value="{!t.DateTime__c}"/>
<apex:column value="{!t.Temperature__c}"/>
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
<apex:pageBlock ><h1>一日の平均気温</h1>
<apex:pageBlockSection columns="1">
<apex:pageBlockTable value="{!tempera_list_by_date}" var="t2" styleClass="dataTable2">
<apex:column value="{!t2.City__c}"/>
<apex:column>
<apex:facet name="header">{!$ObjectType.Temperature__c.Fields['DateTime__c'].Label}</apex:facet>
<apex:outputText value="{0, date, yyyy'/'MM'/'dd}">
<apex:param value="{!t2.DateTime__c}"/>
</apex:outputText>
</apex:column>
<apex:column value="{!t2.Temperature__c}"/>
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
<link class="component" href="//cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="//cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" language="javascript">
var j$ = jQuery.noConflict();
j$('table.dataTable').dataTable({
sPaginationType: "full_numbers"
});
j$('table.dataTable2').dataTable({
sPaginationType: "full_numbers"
});
</script>
</apex:component>
view raw temperature.vfc hosted with ❤ by GitHub
<apex:page tabStyle="Temperature__c">
<c:temperature ></c:temperature>
</apex:page>
view raw temperature.vfp hosted with ❤ by GitHub
global with sharing class TemperatureController {
public List<Temperature__c> tempera_list_by_time {get; set;}
public List<Temperature__c> tempera_list_by_date {get; set;}
global TemperatureController() {
this.tempera_list_by_time = [SELECT City__c, DateTime__c, Temperature__c
FROM Temperature__c];
DateTime dt = this.tempera_list_by_time[0].DateTime__c;
AggregateResult[] results = [SELECT City__c, AVG(Temperature__c) AVG_TEMPERA
FROM Temperature__c
GROUP BY City__c
];
this.tempera_list_by_date = new List<Temperature__c>();
for(AggregateResult result : results) {
Temperature__c temperature = new Temperature__c();
temperature.City__c = (String)result.get('City__c');
temperature.DateTime__c = dt.addHours(9);
temperature.Temperature__c = Integer.valueOf(result.get('AVG_TEMPERA'));
this.tempera_list_by_date.add(temperature);
}
}
}
このようにすると、冒頭の画像のように

  • ページング
  • 検索
  • ソート
機能を表に付けることができた。

気をつけなければいけないのは、このページング・検索・ソート機能は都度 SOQL をクエリするのではなく、初めに取得したレコードの表示順を変えているという点。

なぜかというと、SOQLは確かガバナ制限で5万件までしか結果を取得できなかったはず。
なので、例えば5万1件あるレコードに対して、表のヘッダー行クリックで ASC -> DESC のようにソートした時、5万件目のレコードが一番上に表示されることになってしまう。(本来、5万1件目が一番上に表示されてほしい)

まあ、直近5万件も一気に取得することはないと思う。。。
なので、これで十分という気がしている。

コメント

このブログの人気の投稿

[PC] nx4820 と Debian と無線LAN (2/3)

MAMMUT Rock Pro SE (black 28L) は通勤にもすごく良さげ