Skip to content

Instantly share code, notes, and snippets.

@rs77
Last active February 14, 2023 14:23
Show Gist options
  • Save rs77/eb460684e683fb22a71fbb4aa7edc764 to your computer and use it in GitHub Desktop.
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/
/**
* @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