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


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

カスタムコンポーネントの動的選択リストの作成 に記載がある通りなのですが、最近まで全然知らなかった。 Apex はまじで奥が深い・・・。

Lightning アプリケーションビルダーでコンポーネントが設定されるときに、コンポーネントのプロパティを選択リストとして公開できます。選択リストの値は、作成する Apex クラスによって提供されます。

VisualEditor を使う

Apex のライブラリには、 VisualEditor という名前空間があります。
これに含まれる DynamicPickList クラスを継承したカスタムクラスを Lightning コンポーネントのデザインファイルにデータソースとして指定する事で、アプリケーションビルダーで動的な選択リストを表示する事が出来ます。

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;
    }
}
MyCustomPickList.design
<design:component>
        <design:attribute name="property1" datasource="apex://MyCustomPickList"/>
</design:component>

SObject のリストを表示する

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

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;
    }
}
SObjectPickListSample.design
<design:component>
    <design:attribute name="objectName" label="Salesforce Object Name" datasource="apex://SObjectTypes"/>
</design:component>