Expanding on my comment re: use of the Google Sheets REST API to access and modify row/column groupings:
Row/Column groups are metadata associated with a Sheet
resource, and as such can be obtained for all sheets in a workbook with a single HTTP request to spreadsheets.get
, with the appropriate fields
specification:
GET https://sheets.googleapis.com/v4/spreadsheets/{YOUR_SPREADSHEET_ID}?fields=sheets(columnGroups%2Cproperties(sheetId%2Ctitle)%2CrowGroups)&key={YOUR_API_KEY}
Demo link
The above request returns an object with a sheets
property, which is an array of objects (1 per sheet in the spreadsheet) having 3 properties: rowGroups
, columnGroups
, and properties
. The group properties are arrays of DimensionGroup
objects, while the properties
object contains the sheet's gridId/sheetId, which you need for identifying the sheet in various API requests, and its name (which may be useful for your own script logic).
To delete every row/column group, you need to issue as many DeleteDimensionGroupRequest
s to do so as the maximum depth
returned in your query's groups. If you do not specify the indices of the DimensionRange
in your request, this is interpreted as the whole range of the spreadsheet (all rows / all columns, depending on direction).
An example request (requires OAuth authentication, not just API key):
POST https://sheets.googleapis.com/v4/spreadsheets/{YOUR SPREADSHEET ID}:batchUpdate?fields=replies%2FdeleteDimensionGroup
{
"requests": [
{
"deleteDimensionGroup": {
"range": {
"sheetId": "{SHEET 1 ID}",
"dimension": "COLUMNS"
}
}
},
{
"deleteDimensionGroup": {
"range": {
"sheetId": "{SHEET 2 ID}"
"dimension": "COLUMNS",
}
}
},
...
]
}
Demo link
Each delete request has a reply response, and that response will be very similar to the initial response you got for the row/column groups from the initial query. If you knew the gridIds beforehand, you could forgo the initial query and use a while loop to keep sending delete requests while the response contains a dimension group.
To use these methods with Google Apps Script, you can either use UrlFetchApp
with raw URL resources, or take advantage of the available "advanced service" client library Sheets
(which must first be enabled). Both methods require you to enable use of the Sheets API from your script's Google Cloud Platform project page.
An example using the enabled client library Sheets
:
function removeAllGroups() {
const wb = SpreadsheetApp.getActive(),
wbId = wb.getId();
const initial = Sheets.Spreadsheets.get(wbId, {
fields: "sheets(columnGroups,properties(sheetId,title),rowGroups)"
});
// Determine the maximum depth of row & column groups on each sheet in the workbook.
const maxDepths = {row: {}, col: {}};
initial.sheets.forEach(function (s) {
// if (s.properties.title ... (could write logic to do this only for certain sheets)
var sId = s.properties.sheetId;
if (s.columnGroups && s.columnGroups.length)
maxDepths.col[sId] = s.columnGroups.reduce(dgMaxDepth_, 0);
if (s.rowGroups && s.rowGroups.length)
maxDepths.row[sId] = s.rowGroups.reduce(dgMaxDepth_, 0);
});
// Add all delete requests to an array
const rqs = [];
for (var rqType in maxDepths) {
for (var sheetId in maxDepths[rqType]) {
addDeleteDGRequests_(rqs, rqType, sheetId, maxDepths[rqType][sheetId]);
}
}
// Send all requests.
if (rqs.length) {
const replies = Sheets.Spreadsheets.batchUpdate({requests: rqs}, wbId);
console.log({message: "Batch response", response: replies});
}
}
// Callback for Array#reduce
function dgMaxDepth_(val, dg, i, allDGs) {
return Math.max(val, dg.depth);
}
function addDeleteDGRequests_(requests, rqType, sheetId, num) {
const dim = rqType === "col" ? "COLUMNS" : "ROWS";
while (num > 0) {
var rq = {
deleteDimensionGroup: {
range: { sheetId: sheetId,
dimension: dim }
}
};
requests.push(rq);
--num;
}
}
Resources: