【Visualforce+Apex】複数選択リストをチェックボックスで選択できるようにする。
Visualforceにて複数選択リストをapex:inputFieldで実装すると、標準でこんな感じのUIになります。

これが使いづらいという意見があったりします。個人的には別にそんなに使いづらいとは思わないのですが、チェックボックスで選べてしまった方が使いやすいかも、と思う場面も確かにあるっちゃあります。
ということで複数選択リストのチェックボックス化をやってみます。
選択リストをチェックボックスで表示する
選択リストをチェックボックス化する情報はけっこう豊富で、例えばこの辺の公式フォーラムを参考にすれば比較的すぐに実現できます。
選択リストをチェックボックスで表示
とりあえず上記ソースを参考に、サクッとやっちゃいます。ほぼ流用です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!-- Visualforceページ --> <apex:page id="pg" controller="MultiSelectSampleController"> <apex:form id="frm"> <apex:pageBlock id="pb" title="サンプル"> <apex:pageBlockSection id="pbs" title="複数選択サンプル" > <apex:selectCheckboxes label="スキル" value="{!selections}" > <apex:selectOptions value="{!options}"/> </apex:selectCheckboxes> </apex:pageBlockSection> <apex:pageBlockButtons> <apex:commandButton value="ボタン" action="{!proc}" /> </apex:pageBlockButtons> </apex:pageBlock> </apex:form> </apex:page> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/** * Apexコントローラ. */ public class MultiSelectSampleController { public List<String> selections = new List<String> {}; public List<String> getSelections() { return selections; } public void setSelections(List<String> values) { this.selections = values; } public List<SelectOption> getOptions() { List<SelectOption> options = new list<SelectOption>(); // ↓ここで対象のオブジェクトと項目を指定 Schema.DescribeFieldResult fieldResult = Sample__c.Skill__c.getDescribe(); List<Schema.PicklistEntry> pickListEntry = fieldResult.getPicklistValues(); for (Schema.PicklistEntry pick: pickListEntry) { options.add(new selectOption(pick.getValue(), pick.getLabel())); } return options; } public MultiSelectSampleController() { } // ボタン押下時処理 public void proc() { System.debug('selections = ' + selections); } } |
これを実行すると・・

いい感じになります。
(ラベルとコンテンツの位置が若干ズレているのは・・今回はスルーです)
ちなみにこの「スキル」という項目の選択値、オブジェクト定義的にはこんな感じに、わざと値とAPI参照名を変えています。

Apex側でちゃんとAPI参照名が取得できるのか確認してみると・・

Debug Log: DEBUG|selections = (2, 4) |
ちゃんとAPI名を参照できているようです。
選択項目が多いと見た目がイマイチ。apex:selectCheckboxesは折り返しができない
前述のように選択項目が数個程度だとイイ感じなのですが、選択項目が多くなると見た目がイマイチ。下記は47都道府県の選択リストをチェックボックス化した例。

イイ感じの幅で折り返せないのかな、と思ったのですが、公式のフォーラムでも話題となっている通りで<apex:selectCheckboxes>にそういうオプションは無いらしいです。
Visualforce 開発者ガイド apex:selectCheckboxes
唯一あるのが、チェックボックスを横並びではなく縦並びにするオプション。layout属性にpageDirectionを指定すればできます。
1 |
<apex:selectCheckboxes label="居住経験" value="{!selections}" layout="pageDirection"> |
縦並びの見た目は・・・正直微妙ですね。これだったら標準UIの方が使いやすいと思います。

<apex:selectCheckboxes>を使わずにチェックボックスを表示する
<apex:selectCheckboxes>ではチェックボックスを横か縦に1列でしか並べられない。チェックボックスの数が少なければいいのだけれど、多いと見た目がイマイチ。
ということで<apex:selectCheckboxes>を使わずにチェックボックスを表示して、<apex:pageBlockSection>の columns 属性で列数を制御してみることにします。
下記のような感じに書き換えてみました。SelectOptionのリストではなく、選択値のラベル/値/選択状態で構成される自作クラスのリストを作って、<apex:repeat>でグルグル回して表示しています。Apexクラスはけっこう変わったけどベースとなる書き方はあまり変えていません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- Visualforceページ --> <apex:page id="pg" controller="MultiSelectSampleController"> <apex:form id="frm"> <apex:pageBlock id="pb" title="サンプル"> <apex:pageBlockSection id="pbs" title="居住経験" > <apex:repeat var="sList" value="{!selectionList}"> <apex:outputText value="{!sList.label}"> <apex:inputCheckbox value="{!sList.check}" /> </apex:outputText> </apex:repeat> </apex:pageBlockSection> <apex:pageBlockButtons> <apex:commandButton value="ボタン" action="{!proc}" /> </apex:pageBlockButtons> </apex:pageBlock> </apex:form> </apex:page> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/** * Apexコントローラ. */ public class MultiSelectSampleController { // 選択値リスト public List<Selection> selectionList{get; set;} // 選択値クラス public class Selection { public String label{get; set;} public String value{get; set;} public Boolean check{get; set;} public Selection(String label, String value, Boolean check) { this.label = label; this.value = value; this.check = check; } } // コンストラクタ public MultiSelectSampleController() { this.selectionList = new List<Selection>(); // ↓ここで対象のオブジェクトと項目を指定 Schema.DescribeFieldResult fieldResult = Sample__c.ExperienceLive__c.getDescribe(); List<Schema.PicklistEntry> pickListEntry = fieldResult.getPicklistValues(); for (Schema.PicklistEntry pick: pickListEntry) { Selection selection = new Selection(pick.getValue(), pick.getLabel(), false); this.selectionList.add(selection); } } // ボタン押下時処理 public void proc() { for (Selection selection : this.selectionList) { if (selection.check) { System.debug('label=' + selection.label + ',value=' + selection.value); } } } } |
とりあえずこの状態でこんな見た目になります。

<apex:pageBlockSection>はデフォルト2列表示なので、あとはcolumns属性で8列表示くらいにしてあげればイイ感じかな。
1 |
<apex:pageBlockSection id="pbs" title="居住経験" column="8"> |
で、できた見た目がこれ。

なんだこれ!4列目以降がグシャってなってる!
これ、<apex:pageBlockSection>のAPI仕様をよく読んでみると、columns属性の説明にこんなことが書いてありました。
Visualforce 開発者ガイド apex:pageBlockSection
pageBlockSection には 1 つ以上の列を指定できますが、 Salesforce スタイルシートは 1 つまたは 2 つの列に対して最適化されています。 |
まじか!整って表示されるのは2列までってか。
勉強になったぜバカヤロウ。
素直にスタイルをあててみる
ちょっと変則的なことをやろうとしたら、やっぱりちゃんとcssを書いてあげないとダメみたいですね。サクッとできると思ったら意外と手間取ってしまいました。
結局<apex:pageBlockSection>配下でやろうとすると上手くいかないので、<apex:pageBlockSection>も取っ払って、下記を参考にスタイルをあててみます。
リキッド・レイアウトでチェックボックスを綺麗に並べる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<!-- Visualforceページ --> <apex:page id="pg" controller="MultiSelectSampleController"> <html> <head> <style type="text/css"> #sample2 label { display: block; float: left; width: 110px; } </style> </head> <body> <apex:form id="frm"> <table> <tr><td> <div id="sample2"> <apex:repeat var="sList" value="{!selectionList}"> <label> <apex:inputCheckbox value="{!sList.check}" /> <apex:outputText value="{!sList.label}" /> </label> </apex:repeat> </div> </td></tr> <tr><td> <apex:commandButton value="ボタン" action="{!proc}" /> </td></tr> </table> </apex:form> </body> </html> </apex:page> |
なんかボタン配置がうまくいかなくて、ついでに<apex:pageBlock>も取っ払ってしまった(原因は割愛)。
結果的に見た目はこんな感じです。

ふむふむ、いいですねー。画面幅によって自動で折り返してもくれます。
ここまでやってしまうなら、このチェックボックス選択画面をポップアップ画面として外出ししてしまうのもアリかもしれないですね。親画面と小画面の値渡しと組み合わせればできそう。
【Apex+Visualforce】親画面と小画面で値を受け渡すサンプル
親画面のイメージはこんな感じですかね。選択ボタンをクリックするとチェックボックス選択画面が開いて、選択結果を親画面にラベル表示する、みたいな。

チェックボックス選択画面には全選択/全解除のボタンを付けるとより便利かもしれない。今回はそこまでは作らないけど、機会があればやってみようと思います。