本篇參考:salesforce 零基礎學習(六十二)擷取sObject中類型為Picklist的field values(含record type)
https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_wire_adapters_picklist_values
https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_wire_adapters_picklist_values_record
Salesforce lwc中給我們提供了很多優秀的wire adapter使我們的開發更加便捷,比如getPicklistValues以及
getPicklistValuesByRecordType
可以實作擷取某個字段或者某個record type所有picklist類型字段的 picklist values。這個元件在便捷的同時又讓我們心生哀怨,因為他不是所有的對象都支援,針對常用對象 Account / Opportunity / Contact 或者自定義對象等可以直接使用,友善快捷,但是針對一些對象則不支援,比如 Event & Task。 是以當項目中使用到 Event & Task 進行自定義開發需要擷取某個或者某些字段的 picklist values的值時,如果需求不變,我們進行 hard code,将所有的 label-value鍵值對使用 {label,value}的map進行封裝,此種需求隻是針對不經常修改的場景。如果需求不明确,或者需要指定的record type顯示指定的picklist values,而 record type配置的 picklist values又可以實時變動的場景來說簡直是災難的,是以有了這篇的針對 LwC公用的方法的實作思路。代碼并不完善,思路僅供參考。
思路分析:
1. 背景如何建構,需要滿足哪些場景;
2. 前台如何搭建,如何做成公用元件使大部分的場景都可以簡單引用便可以使用。
伴随着這兩個問題進行了考慮。
1) 針對背景搭建,暫時滿足兩個場景
- 針對一個表可以擷取到所有的 Picklist類型字段的所有的 Picklist值;
- 針對一個表的某個字段(可包含 record type)擷取對應的Picklist值。
2)針對前台的搭建,因為需要從背景擷取資料,需要保證資料擷取支援異步處理,即資料處理完進行picklist 資料指派。
思路分析以後進行功能的建構,本篇參考以前寫過的一篇文章,這裡 PicklistDescriber代碼便不在放出,直接引用。
一. 背景搭建
CommonUtilsController:因為Salesforce目前沒有針對 包含 record type對應的 Picklist values的特别好的擷取方法,是以我們根據以前的XML解析模式進行擷取包含record type的場景。 很多人可能會說Salesforce支援了通過user interface方式擷取,隻需要一個callout就可以擷取到包含record type對應的picklist字段對應的values。這種方式其實和wire adapter原理一樣,隻是針對一部分object,而不是針對所有的object,考慮到元件的共用性,是以放棄了那種方式。
public without sharing class CommonUtilsController {
private static Map<String,Schema.SObjectType> globalDescribeMap = Schema.getGlobalDescribe();
@AuraEnabled(cacheable=true)
public static Map<String,Map<String,String>> getPicklistMapByObject(String objectName) {
Map<String,Map<String,String>> resultMap = new Map<String, Map<String,String>>();
Schema.DescribeSObjectResult objectResult = getDescribeObjectResult(objectName);
Map<String,SObjectField> fieldsMap = objectResult.fields.getMap();
Map<String,Schema.DescribeFieldResult> picklistName2DescribeFieldMap = new Map<String,Schema.DescribeFieldResult>();
for(String fieldName : fieldsMap.keySet()) {
SObjectField objField = fieldsMap.get(fieldName);
Schema.DescribeFieldResult fieldResult = objField.getDescribe();
if(fieldResult.getType() == Schema.DisplayType.Picklist) {
picklistName2DescribeFieldMap.put(fieldName,fieldResult);
}
}
if(!picklistName2DescribeFieldMap.isEmpty()) {
for(String fieldName : picklistName2DescribeFieldMap.keySet()) {
Schema.DescribeFieldResult fieldResult = picklistName2DescribeFieldMap.get(fieldName);
List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();
Map<String,String> fieldValue2LabelMap = new Map<String,String>();
for(Schema.PicklistEntry picklistEntry : picklistEntries) {
if(picklistEntry.isActive()) {
fieldValue2LabelMap.put(picklistEntry.getValue(),picklistEntry.getLabel());
}
}
resultMap.put(fieldName,fieldValue2LabelMap);
}
}
return resultMap;
}
@AuraEnabled(cacheable=true)
public static Map<String,String> getPicklistMapByObjectAndField(String objectName,String field,String recordTypeDevelopName) {
Map<String,String> resultMap = new Map<String,String>();
Schema.DescribeSObjectResult objectResult = getDescribeObjectResult(objectName);
Map<String,SObjectField> fieldsMap = objectResult.fields.getMap();
if(fieldsMap.containsKey(field)) {
SObjectField objField = fieldsMap.get(field);
Schema.DescribeFieldResult fieldResult = objField.getDescribe();
List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();
for(Schema.PicklistEntry picklistEntry : picklistEntries) {
if(picklistEntry.isActive()) {
resultMap.put(picklistEntry.getValue(),picklistEntry.getLabel());
}
}
if(String.isNotBlank(recordTypeDevelopName)) {
List<String> picklistValueWithRecordTypeList = PicklistDescriber.describe(objectName,recordTypeDevelopName,field);
Map<String,String> resultForRecordTypeMap = new Map<String,String>();
for(String picklistValue : picklistValueWithRecordTypeList) {
if(resultMap.containsKey(picklistValue)) {
resultForRecordTypeMap.put(picklistValue,resultMap.get(picklistValue));
}
}
return resultForRecordTypeMap;
}
}
return resultMap;
}
private static Schema.DescribeSObjectResult getDescribeObjectResult(String objectName) {
Schema.SObjectType objectType = globalDescribeMap.get(objectName);
Schema.DescribeSObjectResult objectResult = objectType.getDescribe();
return objectResult;
}
}
背景就這樣搭建完成,暴露了兩個方法:getPicklistMapByObject & getPicklistMapByObjectAndField。第一個方法用來擷取一個表的所有 Picklist類型字段的label api name對,key為api name,value為picklist的label。我們以 Account表為例,傳回的結構類似如下圖所示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuITNwcTO0MzNtkDOxQTN1QjMyUDM0ADMyAjMtYjN5ATM58CX0ADMyAjMvwlN2kDMxkzLcd2bsJ2Lc12bj5ycn9Gbi52YuAjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
第二個方法用來擷取某個指定object指定字段的 picklist values的擷取,有record type則傳遞,如果不需要record type則傳遞 null或者不傳遞即可。針對結果集來說則沒有外層的field api name,直接就是 picklist 字段的 api value -> label,這裡不做截圖。
二. 前台搭建
這裡需要分成兩步, 第一步是做一個公用元件來實作 傳遞相關參數擷取指定的我們想得到的結果集。
picklistUtils.js:封裝了兩個公用函數,getAllPicklist用于擷取object所有的picklist 類型字段的結果集;getFieldPicklistMap用于通過object & field [record type developer name]來擷取指定字段的結果集。
import getPicklistMapByObject from '@salesforce/apex/CommonUtilsController.getPicklistMapByObject';
import getPicklistMapByObjectAndField from '@salesforce/apex/CommonUtilsController.getPicklistMapByObjectAndField';
const getAllPicklist = (objectAPIName) => {
//let resultMap = new Map();
return getPicklistMapByObject({objectName:objectAPIName})
.then(result => {
return result;
})
.catch(error =>{
console.log(error);
});
};
const getFieldPicklistMap = (objectAPIName, fieldAPIName, recordTypeDevelopName) => {
return getPicklistMapByObjectAndField({objectName:objectAPIName,field:fieldAPIName,recordTypeDevelopName:recordTypeDevelopName})
.then(result => {
return result;
})
.catch(error =>{
console.log(error);
});
}
export {getAllPicklist,getFieldPicklistMap};
當我們将代碼指派粘貼到vs code裡面,我們會發現他有一個提示: This may be converted to an async function.為什麼會有這樣的提示呢?是因為我們這個從背景進行結果集擷取,此步驟不是實時的,而是一個異步的操作,是以他提示了将會将這個轉換成了一個異步的函數。
這樣的解釋可能過于幹燥,什麼是異步的?異步怎麼處理呢?這裡放一個連結用來更好的了解:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function。當我們聲明了異步函數,調用源調用它時需要使用await去共同使用,進而實作結果集傳回時可以正常的接收以及處理。
AccountPicklistComponent.js:公共元件搞定以後我們寫一個元件進行測試,下面的元件隻試驗了擷取所有picklist類型字段的測試,其他的方法感興趣的自行測試。
這裡的代碼有幾個關鍵點需要注意:
- 頭部需要引入我們需要用到的函數,這裡引用的是:import {getAllPicklist} from 'c/picklistUtils';
- 我們将生命周期函數connectedCallback使用async聲明成了一個異步函數,因為這裡我們需要有調用異步的函數使用await,是以方法聲明async;
- 針對異步的函數接受結果集需要使用await,否則擷取的結果集變成了同步操作擷取的便是null,隻有通過await進行辨別才可以正常傳回;
- 結果集接受操作需要使用臨時變量,最後将臨時變量指派給我們需要展示前台的變量,不用臨時變量指派不會進行渲染,因為是異步的操作,沒法reactive。
import { LightningElement,track } from 'lwc';
import {getAllPicklist} from 'c/picklistUtils';
export default class AccountPicklistComponent extends LightningElement {
@track industryList = [];
@track typeList = [];
@track accountSourceList = [];
@track ratingList = [];
async connectedCallback() {
const result = await getAllPicklist('Account');
console.log('total result : ' + JSON.stringify(result));
let typeTempList = [];
let industryTempList = [];
let accountSourceTempList = [];
let ratingTempList = [];
for(let key in result) {
if (result.hasOwnProperty(key)) { // Filtering the data in the loop
if(key === 'type') {
let typeResult = result[key];
console.log('type result : ' + JSON.stringify(typeResult));
for(let typeValue in typeResult) {
typeTempList.push({label:typeResult[typeValue],value:typeValue});
}
} else if(key === 'industry') {
let industryResult = result[key];
for(let industryValue in industryResult) {
industryTempList.push({label:industryResult[industryValue],value:industryValue});
}
} else if(key === 'accountsource') {
let accountSourceResult = result[key];
for(let accountSourceValue in accountSourceResult) {
accountSourceTempList.push({label:accountSourceResult[accountSourceValue],value:accountSourceValue});
}
} else if(key === 'rating') {
let ratingResult = result[key];
for(let ratingValue in ratingResult) {
ratingTempList.push({label:ratingResult[ratingValue],value:ratingValue});
}
}
}
}
this.typeList = typeTempList;
this.industryList = industryTempList;
this.accountSourceList = accountSourceTempList;
this.ratingList = ratingTempList;
}
}
accountPicklistComponent.html:用來展示相關字段的select option
<template>
<lightning-card>
<lightning-layout multiple-rows="true">
<lightning-layout-item size="6">
<lightning-combobox
name="industry"
label="industry"
options={industryList}>
</lightning-combobox>
</lightning-layout-item>
<lightning-layout-item size="6">
<lightning-combobox
name="type"
label="type"
options={typeList}>
</lightning-combobox>
</lightning-layout-item>
<lightning-layout-item size="6">
<lightning-combobox
name="accountSource"
label="Account Source"
options={accountSourceList}>
</lightning-combobox>
</lightning-layout-item>
<lightning-layout-item size="6">
<lightning-combobox
name="rating"
label="rating"
options={ratingList}>
</lightning-combobox>
</lightning-layout-item>
</lightning-layout>
</lightning-card>
</template>
結果展示:這個表的相關字段的picklist值便可以動态取出
總結:篇中隻是根據某種需求去分析思考并進行代碼的編寫。代碼并沒有進行優化以及異常處理。篇中有錯誤地方還請指出,有不懂歡迎留言。有更好的方式歡迎溝通。
作者:zero
部落格位址:http://www.cnblogs.com/zero-zyq/
本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接
個人下載下傳了一些相關學習的PDF檔案,如果需要下載下傳請通路百度雲 點選此處通路 密碼:jhuy
如果文章的内容對你有幫助,歡迎點贊~
為友善手機端檢視部落格,現正在将部落格遷移至微信公衆号:Salesforce零基礎學習,歡迎各位關注。