专栏首页salesforce零基础学习Salesforce LWC学习(十五) Async 以及 Picklist 公用方法的实现

Salesforce LWC学习(十五) Async 以及 Picklist 公用方法的实现

本篇参考: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表为例,返回的结构类似如下图所示:

第二个方法用来获取某个指定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值便可以动态取出

总结:篇中只是根据某种需求去分析思考并进行代码的编写。代码并没有进行优化以及异常处理。篇中有错误地方还请指出,有不懂欢迎留言。有更好的方式欢迎沟通。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Salesforce与微信公众号集成实现输入关键字搜索文章

    本篇参考微信官方文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Ac...

    用户1169343
  • salesforce零基础学习(七十五)浅谈SOSL(Salesforce Object Search Language)

    在工作中,我们更多操作的是一个表的对象,所以我们对SOQL的使用很多。但是有时候,我们需要对几个表进行查询操作,类似salesforce的全局搜索功能,这时,使...

    用户1169343
  • salesforce lightning零基础学习(十六) 公用组件之 获取字段label信息

    我们做的项目好多都是多语言的项目,针对不同国家需要展示不同的语言的标题。我们在classic中的VF page可谓是得心应手,因为系统中已经封装好了我们可以直接...

    用户1169343
  • 【赵强老师】Flink的DataSet算子

    Flink为了能够处理有边界的数据集和无边界的数据集,提供了对应的DataSet API和DataStream API。我们可以开发对应的Java程序或者Sca...

    赵强老师
  • java-小程序微信支付

    哈喽 我是你们的KingYiFan,一直说把微信支付给分享出来一直没有机会。终于闲下来了。听着音乐给你们分享一下。不懂可以随时联系我。。

    猿码优创
  • Flink消费kafka如何获取每条消息对应的topic

    shengjk1
  • Java8 Stream

    Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不相关的东西。

    三分恶
  • 接口的编写与测试

    https://wap.ztestin.com/site/register?usercode=FAAAQwMQGAAXAwQBA3QhExcDHAQDPjVaA...

    小老鼠
  • Map排序

    Map排序的方式有很多种,这里记录下自己总结的两种比较常用的方式:按键排序(sort by key), 按值排序(sort by value)。 按键排序(...

    xiangzhihong
  • 玩转字符串篇--替换的鬼斧神工

    张风捷特烈

扫码关注云+社区

领取腾讯云代金券