【Visualforce+Apex】複数選択リストをチェックボックスで選択できるようにする。

Salesforce

Visualforceにて複数選択リストをapex:inputFieldで実装すると、標準でこんな感じのUIになる。

これが使いづらいという意見がある。個人的には別に使いづらいとは思わないが、チェックボックスで選べちゃった方が使いやすいかも、とは思う。

ということで複数選択リストのチェックボックス化をやってみる。

選択リストをチェックボックスで表示する

選択リストをチェックボックス化する情報はけっこう豊富で、例えばこの辺の公式フォーラムを参考にすれば比較的すぐに実現できる。
選択リストをチェックボックスで表示

とりあえず上記ソースを参考に、サクッとやっちゃいます。ほぼ流用です。

<!-- 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>
/**
 * 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)

バッチリでした。

選択項目が多いと見た目がイマイチ。apex:selectCheckboxesは折り返しができない

前述のように選択項目が数個程度だとイイ感じなのですが、選択項目が多くなると見た目がイマイチ。下記は47都道府県の選択リストをチェックボックス化した例。

イイ感じの幅で折り返せないのかな、と思ったが、公式のフォーラムでも話題となっている通りで<apex:selectCheckboxes>にそういうオプションは無いらしい。
Visualforce 開発者ガイド apex:selectCheckboxes

唯一あるのが、チェックボックスを横並びではなく縦並びにするオプション。layout属性にpageDirectionを指定する

<apex:selectCheckboxes label="居住経験" value="{!selections}" layout="pageDirection">

縦並びの見た目は・・・うーん微妙。たぶん標準UIの方が使いやすい。

<apex:selectCheckboxes>を使わずにチェックボックスを表示する

<apex:selectCheckboxes>ではチェックボックスを横か縦に1列でしか並べられない。チェックボックスの数が少なければいいのだけれど、多いと見た目がイマイチ。

ということで<apex:selectCheckboxes>を使わずにチェックボックスを表示して、<apex:pageBlockSection>の columns 属性で列数を制御してみることにする。

下記のような感じに書き換えてみた。SelectOptionのリストではなく、選択値のラベル/値/選択状態で構成される自作クラスのリストを作って、<apex:repeat>でグルグル回して表示している。Apexクラスはけっこう変わったけどベースとなる書き方はあまり変えてない。

<!-- 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>
/**
 * 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列表示くらいにしてあげればイイ感じかな。

<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>も取っ払って、下記を参考にスタイルをあててみる。
リキッド・レイアウトでチェックボックスを綺麗に並べる

<!-- 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】親画面と小画面で値を受け渡すサンプル

親画面のイメージはこんな感じですかね。選択ボタンをクリックするとチェックボックス選択画面が開いて、選択結果を親画面にラベル表示する、みたいな。

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

コメント

タイトルとURLをコピーしました