alexed1 / LightningFlowComponents

A collection of unofficial Flow extensions that can be used to enhance Salesforce Flow and Orchestrator.
http://unofficialsf.com
Other
594 stars 583 forks source link

Multiselect Magic: Manage Multiselect Picklists with Flow - NullPointerException #757

Open KARtedweaver opened 3 years ago

KARtedweaver commented 3 years ago

To create this issue load the values of an empty selected list into the component.

The returned error: apex error. System.NullPointerException: Attempt to de-reference a null object

CalvinNelson-occmgmt commented 3 years ago

@adwhite75 what is the status on this? The action basically does not work at all without the fix.

adwhite75 commented 3 years ago

Thanks for your patience - this is all largely volunteer based and I flagged this as needing a dev.

To clarify, @KARtedweaver and @CalvinNelson-occmgmt are you all seeing this on a null record or a null/empty 'targetValue' input?

adwhite75 commented 3 years ago

@CalvinNelson-occmgmt / @KARtedweaver would you all be able to try out this new code before we publish a fix? It worked for me but I wanted to check with you both first.

https://gist.github.com/adwhite75/8cfb1efafe3b745d4bf4a8e3f5847652

KARtedweaver commented 3 years ago

Still getting the APEX error when selected values is blank on the target record

Also getting an error when I try to use ReturnStringCollection Error Occurred: An Apex error occurred: ManageMultiselectField.InvocableActionException: You provided an invalid value for the operation value

From: adwhite75 @.> Date: Friday, September 10, 2021 at 9:30 AM To: alexed1/LightningFlowComponents @.> Cc: Weaver, Ted (CONTRACTOR) @.>, Mention @.> Subject: Re: [alexed1/LightningFlowComponents] Multiselect Magic: Manage Multiselect Picklists with Flow - NullPointerException (#757)

@CalvinNelson-occmgmthttps://github.com/CalvinNelson-occmgmt / @KARtedweaverhttps://github.com/KARtedweaver would you all be able to try out this new code before we publish a fix? It worked for me but I wanted to check with you both first.

`public with sharing class ManageMultiselectField {

@InvocableMethod(label='Manage Multiselect Field' description='Carries out a specified operation on the value of a specified multiselect field')

public static List execute(List requests) {

List<Response> results = new List<Response>();

for (Request curRequest : requests) {

    Response curResponse = new Response();

    //verify type of specified field

    validateFieldType(curRequest);

    List<String> selectedValueList = new List<String>();

           List<String> availableValuesList = new List<String>();

    if (curRequest.operation != null && curRequest.curRecord != null) {

        String fieldValue = (String)curRequest.curRecord.get(curRequest.fieldApiName);

        selectedValueList = fieldValue.split(';');

        availableValuesList = getPicklistValues(curRequest.objectApiName, curRequest.fieldApiName);

        switch on curRequest.operation {

            when 'CheckForValue' {

                System.debug('selected values are: ' + selectedValueList);

                if (selectedValueList.contains(curRequest.targetValue)) {

                    curResponse.targetPresent= true;

                } else curResponse.targetPresent = false;

            }

            when 'AddValue' {

            //    if (curRequest.targetValue != null && !selectedValueList.contains(curRequest.targetValue)) {

                    //verify that the targetValue is an allowed value

                    if (curRequest.targetValue != null && availableValuesList.contains(curRequest.targetValue)) {

                        selectedValueList.add(curRequest.targetValue);

                    }

                    if (curRequest.targetValue != null && !availableValuesList.contains(curRequest.targetValue)) {

                    throw new InvocableActionException('The value: ' + curRequest.targetValue + 'is not an allowed value for the picklist: ' + curRequest.fieldApiName + ' in object: ' + curRequest.objectApiName);

                    }

            }

            when 'RemoveValue' {

                //System.debug('selected values are: ' + selectedValueList);

                if (curRequest.targetValue != null && selectedValueList.contains(curRequest.targetValue)) {

                    Integer counter = 0;

                    for(Integer x = 0; x< selectedValueList.size(); x++) {

                        System.debug('x is: ' + x);

                        if (selectedValueList[x] == curRequest.targetValue) {

                            counter = x;

                        }

                    }

                    System.debug('index position is: ' + counter);

                    selectedValueList.remove(counter);

                }

            }

            when else {

                throw new InvocableActionException('You provided an invalid value for the operation value');

            }

        }

    }

    curResponse.selectedValuesList = selectedValueList;

    curResponse.availableValuesList = availableValuesList;

    curResponse.selectedValuesSemicolonString = String.join(selectedValueList, ';');

    System.debug('updated selectedValuesSemicolonString is: ' + curResponse.selectedValuesSemicolonString);

    if (curRequest.saveAutomatically == true) {

        curRequest.curRecord.put(curRequest.fieldApiName, curResponse.selectedValuesSemicolonString);

        update curRequest.curRecord;

    }

    results.add(curResponse);

}

return results;

}

private static List getPicklistValues(String ObjectApi_name,String Field_name){

List<String> lstPickvals=new List<String>();

Schema.SObjectType targetType = Schema.getGlobalDescribe().get(ObjectApi_name);//From the Object Api name retrieving the SObject

Sobject Object_name = targetType.newSObject();

Schema.sObjectType sobject_type = Object_name.getSObjectType(); //grab the sobject that was passed

Schema.DescribeSObjectResult sobject_describe = sobject_type.getDescribe(); //describe the sobject

Map<String, Schema.SObjectField> field_map = sobject_describe.fields.getMap(); //get a map of fields for the passed sobject

List<Schema.PicklistEntry> pick_list_values = field_map.get(Field_name).getDescribe().getPickListValues(); //grab the list of picklist values for the passed field on the sobject

for (Schema.PicklistEntry a : pick_list_values) { //for all values in the picklist list

    lstPickvals.add(a.getValue());//add the value  to our final list

 }

return lstPickvals;

}

private static void validateFieldType(Request curRequest) {

//credit to https://salesforce.stackexchange.com/a/223330/24822

SObjectType r = ((SObject)(Type.forName('Schema.'+curRequest.objectApiName).newInstance())).getSObjectType();

DescribeSObjectResult d = r.getDescribe();

Schema.DisplayType fieldDataType = d.fields

        .getMap()

        .get(curRequest.fieldApiName)

        .getDescribe()

        .getType();

System.debug('data type is: ' + fieldDataType);

if (fieldDataType.name() != 'MULTIPICKLIST')

    throw new InvocableActionException('The specified field is not a multiselect picklist. It may be a standard picklist, in which case you should use a different solution');

}

/ Input parameters for the Apex action /

public class Request{

@InvocableVariable(label='Api name of the target Object' required = true )

public string objectApiName;

@InvocableVariable(label='Api name of the target Field' required = true )

public string fieldApiName;

@InvocableVariable(label='Desired Action to carry out on the target multiselect field' )

public string operation;

@InvocableVariable(label='Target Value')

public string targetValue;

@InvocableVariable(label='SaveAutomatically')

public Boolean saveAutomatically;

@InvocableVariable(label='Input Record')

public SObject curRecord;

}

/ Output parameters of the Apex action /

public class Response{

@InvocableVariable(label='Selected Values, returned as a collection of strings')

public List<String> selectedValuesList;

@InvocableVariable(label='Selected Values, returned as a semicolon string')

public String selectedValuesSemicolonString;

@InvocableVariable(label='Available Values, returned as a collection of strings')

public List<String> availableValuesList;

@InvocableVariable(label='Is Target Present?')

public Boolean targetPresent;

}

public class InvocableActionException extends Exception{}

}`

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/alexed1/LightningFlowComponents/issues/757#issuecomment-916906390, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AO64UFAHLDH4JHUY2JHCHJLUBICAPANCNFSM46DHIR4A. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

adwhite75 commented 3 years ago

Can you take a snap of your action config? I don't have enough info to help debug.

boooney commented 2 years ago

@adwhite75 I'm experiencing the same issue. Happy to help with the debugging if I can.

mkaizad commented 1 year ago

@KARtedweaver, @boooney would it be possible to include a screenshot of your inputs?

boooney commented 1 year ago

Sorry for the delay. I don't think I have that flow anymore. It's been a while.

On Sat, Mar 25, 2023 at 12:11 AM mkaizad @.***> wrote:

@KARtedweaver https://github.com/KARtedweaver, @boooney https://github.com/boooney would it be possible to include a screenshot of your inputs?

— Reply to this email directly, view it on GitHub https://github.com/alexed1/LightningFlowComponents/issues/757#issuecomment-1483748776, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACXCG3OPNK6P6VZNVWRRT4LW52LAJANCNFSM46DHIR4A . You are receiving this because you were mentioned.Message ID: @.***>