連動項目の選択リストを動的に取得・作成したい場合にAPIコールでのみ利用できるValidFor
をApexでも利用できるようにしてしまった猛者がいたので、簡単に使えるように少し修正してみました。
こんな感じで使えます。
SomeObject
というオブジェクトにctrlPicklist
とdepPicklist
という選択リストがあるとして、ctrlPicklist
が制御項目、depPicklist
が連動項目と仮定しています。
Example.apxc
public class Example {
private static String INITIAL_VALUE = '';
// 選択リストで選択された値が格納される変数
public SomeObject objectInstance {get; set;}
public List<SelectOption> DependentPickListOptions{
get{
List<SelectOption> options = new List<SelectOption>();
// 選択リストの一番上にデフォルトの選択値を設定
options.add(new SelectOption(INITIAL_VALUE, '-- なし --'));
// 制御項目ctrlPicklistが選択されている時に連動項目depPicklistで選べる選択肢を取得する。
if( this.objectInstance.ctrlPicklist != null || this.objectInstance.ctrlPicklist != INITIAL_VALUE ){
List<DepPickListCtrl.TPicklistEntry> tPicklistEntries =
DepPickListCtrl.GetDependentOptions('SomeObject','ctrlPicklist','depPicklist').get(this.objectInstance.ctrlPicklist);
for( DepPickListCtrl.TPicklistEntry e : tPicklistEntries ){
options.add(new SelectOption(e.value, e.label));
}
}
return options;
}
}
// コンストラクタ
public Example(){
this.objectInstance = new SomeObject();
}
}
下のApexクラスを同じ組織に一つ追加します。
DepPickListCtrl.apxc
/* Reference
* Great thanks to Neel
* http://titancronus.com/blog/2014/05/01/salesforce-acquiring-dependent-picklists-in-apex/
*/
public class DepPickListCtrl {
public static Map<String,List<DepPickListCtrl.TPicklistEntry>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName){
Map<String,List<DepPickListCtrl.TPicklistEntry>> objResults = new Map<String,List<DepPickListCtrl.TPicklistEntry>>();
//get the string to sobject global map
Map<String,Schema.SObjectType> objGlobalMap = Schema.getGlobalDescribe();
if (!objGlobalMap.containsKey(pObjName))
return objResults;
//get the type being dealt with
Schema.SObjectType pType = objGlobalMap.get(pObjName);
Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap();
//verify field names
if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName))
return objResults;
//get the control values
List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues();
//get the dependent values
List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues();
//iterate through the values and get the ones valid for the controlling field name
DepPickListCtrl.Bitset objBitSet = new DepPickListCtrl.Bitset();
//set up the results
for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){
//get the pointer to the entry
Schema.PicklistEntry ctrl_entry = ctrl_ple[pControllingIndex];
//get the label
String pControllingLabel = ctrl_entry.getLabel();
//create the entry with the label
objResults.put(pControllingLabel,new List<DepPickListCtrl.TPicklistEntry>());
}
//cater for null and empty
objResults.put('',new List<DepPickListCtrl.TPicklistEntry>());
objResults.put(null,new List<DepPickListCtrl.TPicklistEntry>());
//check the dependent values
for(Integer pDependentIndex=0; pDependentIndex<dep_ple.size(); pDependentIndex++){
//get the pointer to the dependent index
Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex];
//get the valid for
String pEntryStructure = JSON.serialize(dep_entry);
DepPickListCtrl.TPicklistEntry objDepPLE = (DepPickListCtrl.TPicklistEntry)JSON.deserialize(pEntryStructure, DepPickListCtrl.TPicklistEntry.class);
//if valid for is empty, skip
if (objDepPLE.validFor==null || objDepPLE.validFor==''){
continue;
}
//iterate through the controlling values
for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){
if (objBitSet.testBit(objDepPLE.validFor,pControllingIndex)){
//get the label
String pControllingValue = ctrl_ple[pControllingIndex].getValue();
objResults.get(pControllingValue).add(objDepPLE);
}
}
}
return objResults;
}
public class TPicklistEntry{
public string active {get;set;}
public string defaultValue {get;set;}
public string label {get;set;}
public string value {get;set;}
public string validFor {get;set;}
public TPicklistEntry(){
}
}
private class Bitset{
public Map<String,Integer> AlphaNumCharCodes {get;set;}
public Map<String, Integer> Base64CharCodes { get; set; }
public Bitset(){
LoadCharCodes();
}
//Method loads the char codes
private void LoadCharCodes(){
AlphaNumCharCodes = new Map<String,Integer>{
'!'=>33,'”'=>34,'#'=>35,'$'=>36,'%'=>37,'&'=>38,'\''=>39,'('=>40,')'=>41,'*'=>42,'+'=>43,','=>44,'-'=>45,
'.'=>46,'/'=>47,'0'=>48,'1'=>49,'2'=>50,'3'=>51,'4'=>52,'5'=>53,'6'=>54,'7'=>55,
'8'=>56,'9'=>57,':'=>58,';'=>59,'<'=>60,'='=>61,'>'=>62,'?'=>63,'@'=>64,
'A'=>65,'B'=>66,'C'=>67,'D'=>68,'E'=>69,'F'=>70,'G'=>71,'H'=>72,'I'=>73,'J'=>74,
'K'=>75,'L'=>76,'M'=>77,'N'=>78,'O'=>79,'P'=>80,'Q'=>81,'R'=>82,'S'=>83,'T'=>84,
'U'=>85,'V'=> 86,'W'=>87,'X'=>88,'Y'=>89,'Z'=>90
};
Base64CharCodes = new Map<String, Integer>();
//lower case
Set<String> pUpperCase = AlphaNumCharCodes.keySet();
for(String pKey : pUpperCase){
//the difference between upper case and lower case is 32
AlphaNumCharCodes.put(pKey.toLowerCase(),AlphaNumCharCodes.get(pKey)+32);
//Base 64 alpha starts from 0 (The ascii charcodes started from 65)
Base64CharCodes.put(pKey,AlphaNumCharCodes.get(pKey) - 65);
Base64CharCodes.put(pKey.toLowerCase(),AlphaNumCharCodes.get(pKey) - (65) + 26);
}
//numerics
for (Integer i=0; i<=9; i++){
AlphaNumCharCodes.put(string.valueOf(i),i+48);
//base 64 numeric starts from 52
Base64CharCodes.put(string.valueOf(i), i + 52);
}
}
public Boolean testBit(String pValidFor,Integer n){
//the list of bytes
List<Integer> pBytes = new List<Integer>();
//multiply by 6 since base 64 uses 6 bits
Integer bytesBeingUsed = (pValidFor.length() * 6)/8;
//will be used to hold the full decimal value
Integer pFullValue = 0;
//must be more than 1 byte
if (bytesBeingUsed <= 1)
return false;
//calculate the target bit for comparison
Integer bit = 7 - (Math.mod(n,8));
//calculate the octet that has in the target bit
Integer targetOctet = (bytesBeingUsed - 1) - (n >> bytesBeingUsed);
//the number of bits to shift by until we find the bit to compare for true or false
Integer shiftBits = (targetOctet * 8) + bit;
//get the base64bytes
for(Integer i=0;i<pValidFor.length();i++){
//get current character value
pBytes.Add((Base64CharCodes.get((pValidFor.Substring(i, i+1)))));
}
//calculate the full decimal value
for (Integer i = 0; i < pBytes.size(); i++)
{
Integer pShiftAmount = (pBytes.size()-(i+1))*6;//used to shift by a factor 6 bits to get the value
pFullValue = pFullValue + (pBytes[i] << (pShiftAmount));
}
//& is to set the same set of bits for testing
//shift to the bit which will dictate true or false
Integer tBitVal = ((Integer)(Math.Pow(2, shiftBits)) & pFullValue) >> shiftBits;
return tBitVal == 1;
}
}
}
動作確認
V35