Salesforce LWC學習(十五) Async 以及 Picklist 公用方法的實現

本篇參考:salesforce 零基礎學習(六十二)獲取sObject中類型爲Picklist的field values(含record type)javascript

https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_wire_adapters_picklist_valueshtml

https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_wire_adapters_picklist_values_recordjava

Salesforce lwc中給咱們提供了不少優秀的wire adapter使咱們的開發更加便捷,好比getPicklistValues以及getPicklistValuesByRecordType react

能夠實現獲取某個字段或者某個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公用的方法的實現思路。代碼並不完善,思路僅供參考。api

思路分析:異步

1. 後臺如何構建,須要知足哪些場景;async

2. 前臺如何搭建,如何作成公用組件使大部分的場景均可以簡單引用即可以使用。函數

伴隨着這兩個問題進行了考慮。oop

1) 針對後臺搭建,暫時知足兩個場景post

  • 針對一個表能夠獲取到全部的 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表爲例,返回的結構相似以下圖所示:

 第二個方法用來獲取某個指定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值即可以動態取出

總結:篇中只是根據某種需求去分析思考並進行代碼的編寫。代碼並無進行優化以及異常處理。篇中有錯誤地方還請指出,有不懂歡迎留言。有更好的方式歡迎溝通。

相關文章
相關標籤/搜索