Last active
February 14, 2023 14:23
-
-
Save rs77/eb460684e683fb22a71fbb4aa7edc764 to your computer and use it in GitHub Desktop.
Google App Script to enable users on a Google Sheet to select multiple options on a dropdown menu. Demonstration and more information here: https://scripteverything.com/google-sheets-drop-down-list-multiple-select/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @param {SheetsOnEdit} e - edit event object | |
*/ | |
function onEdit(e) { | |
/** | |
* @typedef {Object} MultiDropDown | |
* @property {String} namedRange | |
* @property {Number} handlingDuplicates | |
* @property {String} separator | |
* @property {Boolean} sortResult | |
*/ | |
const ddRanges = [{'namedRange': 'ddFruitVeges', 'handlingDuplicates': 1, 'separator': ", ", 'sortResult': true}]; | |
multiSelectDropDownList(e, ddRanges); | |
} | |
/** | |
* @param {SheetsOnEdit} e | |
* @param {MultiDropDown[]} ddRanges | |
* @returns {void} | |
*/ | |
function multiSelectDropDownList(e, ddRanges) { | |
ddRanges.forEach((nr) => { | |
if (!isIntersection(e, nr.namedRange)) return; | |
updateDropDownListCell(e, nr.handlingDuplicates, nr.separator, nr.sortResult); | |
}); | |
} | |
/** | |
* @param {SheetsOnEdit} e - edit event object | |
* @param {String} ddNamedRange | |
* @returns {Boolean} | |
*/ | |
function isIntersection(e, ddNamedRange) { | |
const activeCell = e.range; | |
// is the Active Cell a single cell? | |
if (activeCell.width * activeCell.height > 1) return false; | |
// loop through the array of drop down list named ranges | |
const rngNR = e.source.getRangeByName(ddNamedRange); | |
// is the Active Cell on the same sheet? | |
const shtIdAC = activeCell.getSheet().getSheetId(); | |
const shtIdNR = rngNR.getSheet().getSheetId(); | |
if (shtIdAC !== shtIdNR) return false; | |
// is the Active Cell intersecting within the boundaries of the named range? | |
const colAC = activeCell.getColumn(); | |
const rowAC = activeCell.getRow(); | |
const colNR = rngNR.getColumn(); | |
const rowNR = rngNR.getRow(); | |
const colNRLast = rngNR.getLastColumn(); | |
const rowNRLast = rngNR.getLastRow(); | |
return colAC >= colNR && colAC <= colNRLast && rowAC >= rowNR && rowAC <= rowNRLast; | |
} | |
/** | |
* @param {SheetsOnEdit} e | |
* @param {Number} handlingDuplicates | |
* @param {String} separator | |
* @param {Boolean} sortResult | |
* @returns {Range} | |
*/ | |
function updateDropDownListCell(e, handlingDuplicates, separator, sortResult) { | |
// if cell has been cleared or is a new cell | |
if (!e.value || !e.oldValue) return e.range.setValue(e.value); | |
const oldItems = e.oldValue.split(separator); | |
const idx = oldItems.indexOf(e.value); | |
if (idx > -1) { | |
// if it does, how do you want to handle it? | |
// Option #1: splice the item from the list | |
if (handlingDuplicates === 1) { | |
oldItems.splice(idx, 1); | |
if (sortResult && oldItems.length > 1) oldItems.sort(); | |
return e.range.setValue(oldItems.join(separator)); | |
} | |
// Option #2: exclude it from being added, but do not remove it | |
if (handlingDuplicates === 2) return e.range.setValue(oldItems.join(separator)); | |
// Option #3: add it to the existing list as an additional item | |
// continue with rest of the code | |
} | |
// check if the newly selected item already exists in the active cell | |
// add value to existing items | |
oldItems.push(e.value); | |
if (sortResult) oldItems.sort(); | |
return e.range.setValue(oldItems.join(separator)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment