Page layout snippet of a single picklist value. Notice the oAAA
in the validFor
. The base64 value needs to be decoded to determine which parent items the dependent picklist value is allowed for. See https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_describesobjects_describesobjectresult.htm for more info.
{
"active": true,
"defaultValue": false,
"label": "Canceled",
"validFor": "oAAA",
"value": "Canceled"
}
Helper functions:
/*
Base64 characters: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
A is index 0 so : 000000
I is index 8 so : 001000
Q is index 16 so: 010000
o is index 40 so: 101000
QAAA is 010000 000000 000000 000000
Since binary 1 at 2nd position, not index, means the dependent field is valid option for the 2nd option in parent picklist
IAAA is 001000 000000 000000 000000
Since binary 1 at 3rd position, not index, means the dependent field is valid option for the 3rd option in parent picklist
oAAA is 101000 000000 000000 000000
Since binary 1 at 1st and 3rd position, not index, means the dependent field is valid option for the 1st and 3rd option in parent picklist
Given: 'QAAA', return string like: '010000000000000000000000'
*/
base64EncodingToBinaryBits: (value = '') => {
const base64CharacterSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const characterValues = [...value]; // 'QAAA' becomes ['Q', 'A', 'A', 'A']
const binaryValuesOfCharacterPosition = characterValues.map(character => {
const characterPosition = base64CharacterSet.indexOf(character);
const binaryRadix = 2;
const binaryRepresentation = characterPosition.toString(binaryRadix);
const base64Radix = 6; // 2^6 is 64, 6 is the target length of of string
const base64BinaryRepresentation = binaryRepresentation.padStart(base64Radix, '0'); // adds any needed leading 0's
return base64BinaryRepresentation;
});
const binaryBits = binaryValuesOfCharacterPosition.join('');
return binaryBits;
},
/*
Binary strings are interpreted from left to right
Consider on when the binary value is 1
*/
isBinaryValueOnAtIndex: (binaryStringValue = '', index = 0) => {
const bit = binaryStringValue[index];
const isOn = bit
? bit === '1'
: false;
return isOn;
}
Tests for helpers:
describe('Base64 string decoded to binary string', () => {
it('No position on', () => {
const base64PositionOn = undefined;
const binaryPositionOn = '';
const expectedBinaryPositionOn = stringUtilities.base64EncodingToBinaryBits(base64PositionOn);
expect(expectedBinaryPositionOn).toEqual(binaryPositionOn);
});
it('2nd position on', () => {
const base64PositionOn = 'QAAA';
const binaryPositionOn = '010000000000000000000000';
const expectedBinaryPositionOn = stringUtilities.base64EncodingToBinaryBits(base64PositionOn);
expect(expectedBinaryPositionOn).toEqual(binaryPositionOn);
});
it('1st and 3rd position on', () => {
const base64PositionOn = 'oAAA';
const binaryPositionOn = '101000000000000000000000';
const expectedBinaryPositionOn = stringUtilities.base64EncodingToBinaryBits(base64PositionOn);
expect(expectedBinaryPositionOn).toEqual(binaryPositionOn);
});
});
describe('Binary string values on or off', () => {
it('Value on at index for no binary value, index out of bounds', () => {
const binaryValue = '';
const someRandomOutOfBoundsIndex = 5;
const isIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, someRandomOutOfBoundsIndex);
expect(isIndexOn).toEqual(false);
});
it('Value on at index', () => {
const binaryValue = '101000000000000000000000';
const isFirstIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 0);
const isThirdIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 2);
expect(isFirstIndexOn).toEqual(true);
expect(isThirdIndexOn).toEqual(true);
});
it('Value off at index', () => {
const binaryValue = '101000000000000000000000';
const isSecondIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 1);
const isFourthIndexOn = stringUtilities.isBinaryValueOnAtIndex(binaryValue, 3);
expect(isSecondIndexOn).toEqual(false);
expect(isFourthIndexOn).toEqual(false);
});
});