Lightning コンポーネントの設定で動的な選択リストを表示する

#出来ないと思ってたのです

[カスタムコンポーネントの動的選択リストの作成](https://developer.salesforce.com/docs/atlas.ja-jp.lightning.meta/lightning/components_config_for_app_builder_dynamic_picklists.htm)　に記載がある通りなのですが、最近まで全然知らなかった。　Apex はまじで奥が深い・・・。
> Lightning アプリケーションビルダーでコンポーネントが設定されるときに、コンポーネントのプロパティを選択リストとして公開できます。選択リストの値は、作成する Apex クラスによって提供されます。

![Screen_Shot_2018-05-22_at_16_57_16.png](https://qiita-image-store.s3.amazonaws.com/0/26378/f5709467-d28c-d300-82c8-6f0de9d895a0.png)

# VisualEditor を使う
Apex のライブラリには、 [VisualEditor](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_namespace_VisualEditor.htm) という名前空間があります。
これに含まれる　DynamicPickList クラスを継承したカスタムクラスを Lightning コンポーネントのデザインファイルにデータソースとして指定する事で、アプリケーションビルダーで動的な選択リストを表示する事が出来ます。

```java:MyCustomPickList.apxc
global class MyCustomPickList extends VisualEditor.DynamicPickList{
    
    global override VisualEditor.DataRow getDefaultValue(){
        VisualEditor.DataRow defaultValue = new VisualEditor.DataRow('red', 'RED');
        return defaultValue;
    }
    global override VisualEditor.DynamicPickListRows getValues() {
        VisualEditor.DataRow value1 = new VisualEditor.DataRow('red', 'RED');
        VisualEditor.DataRow value2 = new VisualEditor.DataRow('yellow', 'YELLOW');
        VisualEditor.DynamicPickListRows  myValues = new VisualEditor.DynamicPickListRows();
        myValues.addRow(value1);
        myValues.addRow(value2);
        return myValues;
    }
}
```

```html:MyCustomPickList.design
<design:component>
        <design:attribute name="property1" datasource="apex://MyCustomPickList"/>
</design:component>
```


#SObject のリストを表示する
SObject のリストを選択リストで表示したい時のサンプルコードです。
DataRow　クラスのリストに対して sort がうまく動かなかったので、面倒ですがラッパークラスで一度ソートする事にしました。

```java:SObjectTypes.apxc
global class SObjectTypes extends VisualEditor.DynamicPickList {
    
    // 未選択用の DataRow
    private static final VisualEditor.DataRow EMPTY_DATAROW =  new VisualEditor.DataRow('', null);
    
    // メンバー変数
    private VisualEditor.DesignTimePageContext context; // Lightning コンポーネントが配置されたページの情報
    private VisualEditor.DynamicPickListRows dynamicPickListRows; // 表示する選択肢
    
    // コンストラクター
    // 選択リストを初期化する
    global SObjectTypes(VisualEditor.DesignTimePageContext context) {
        this.context = context;
        
        this.dynamicPickListRows = new VisualEditor.DynamicPickListRows();
        this.dynamicPickListRows.addRow(EMPTY_DATAROW);
        for (SObjectType sObjType : getSortedSObjectTypeList()) {
            this.dynamicPickListRows.addRow(new VisualEditor.DataRow(sObjType.label, sObjType.name));
        }
    }
    
    // デフォルト値を返す
    // レコードページの場合はレコードのおブジェクトタイプを返す。それ以外であれば空白
    global override VisualEditor.DataRow getDefaultValue() {    
        if (context.pageType == 'RecordPage') {
            for (VisualEditor.DataRow row : this.dynamicPickListRows.getDataRows()) {
                if (row.getValue() == context.entityName) return row;
            }
        }
        return EMPTY_DATAROW;
    }
    
    // 選択リストを返す
    global override VisualEditor.DynamicPickListRows getValues() {
        return this.dynamicPickListRows;
    }

    
    // SObject をラベル名で昇順に並べ替えるためのラッパークラス。
    private class SObjectType implements Comparable {
        public String label;
        public String name;      
        public SObjectType(String name) {
            Schema.DescribeSObjectResult dsor = Schema.getGlobalDescribe().get(name).getDescribe();
            this.label = dsor.getLabel(); 
            this.name = dsor.getName(); 
        }
        public Integer compareTo(Object compareTo) {
            SObjectType other = (SObjectType)compareTo;
            if (this.label > other.label) return 1;
            if (this.label < other.label) return -1;
            return 0;
        }
    }
    // ソートされた SObjectType のリストを返す
    private List<SObjectType> getSortedSObjectTypeList() {
        List<SObjectType> ret = new List<SObjectType>();
        for (String name : Schema.getGlobalDescribe().keySet()) {
            ret.add(new SObjectType(name));
        }
        ret.sort();
        return ret;
    }
}
```
```html:SObjectPickListSample.design
<design:component>
    <design:attribute name="objectName" label="Salesforce Object Name" datasource="apex://SObjectTypes"/>
</design:component>
```