I've written a little script that automatically deletes all Sheets my user accidentally create.
Often, when accessing the spreadsheet with their phone, they accidentally click on "+" and create tons of empty sheets, like Sheet101, Sheet102, etc.
My script is very simple: gets all sheets, and if the name starts with Sheet, just deletes it.
It works perfectly, but after deleting all the undesired sheets, the problem is that it automatically unhides the first hidden sheet (some sheets are hidden for practical use, like they contain lists).
For example, if I have the following hidden sheets:
oldform, list1, list2, ...
After executing the script, the sheet oldform will be unhidden, thus appearing to the users.
Here is two codes I've tried:
The simple one:
function DELETESHEETS2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (i = 0; i < sheets.length; i++) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
ss.deleteSheet(sheets[i]);
}
}
}
The one I tried to modify to solve my problem:
function DELETESHEETS3() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (i = 0; i < sheets.length; i++) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
label = sheets[i].getName();
toto = ss.getSheetByName(label);
ss.deleteSheet(toto);
}
}
}
The reverse loop
With this one, the hidden sheet appears at the beginning and not at the end:
function DELETESHEETS2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (i = sheets.length -1; i > 0 ; i--) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
ss.deleteSheet(sheets[i]);
}
}
}
A partial solution
This one works, thanks to #OMila. But it does not explain the weird behavior of a simple loop. Maybe I missed something?
function DELETESHEETS2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var hdnShts = [];
for (var i = 0; i < sheets.length; i++) {
if(sheets[i].isSheetHidden()) {
hdnShts.push(sheets[i].getName()); //saving all the hidden sheet names for later
}
}
for (i = 0; i < sheets.length; i++) {
if ( sheets[i].getName().indexOf("Sheet") > -1 ) {
ss.deleteSheet(sheets[i]);
}
}
for(var i = 0; i<hdnShts.length; i++) {
ss.getSheetByName(hdnShts[i]).hideSheet(); //just to make sure all the hiddens remain hidden
}
}
Thanks for your help if you have any idea!
PS: this problem is easy to reproduce, just create lots of sheets including one with a name other than Sheetxxx
Try this:
function delSheetsKeepHidden() {
var ss = SpreadsheetApp.getActive();
var shts = ss.getSheets();
var hdnShts = [];
for (var i = 0; i < shts.length; i++) {
if(shts[i].isSheetHidden()) {
hdnShts.push(shts[i].getName()); //saving all the hidden sheet names for later
}
}
for(var i = 0; i < shts.length; i++) {
if(shts[i].getName().slice(0,5).toLowerCase() == "sheet") {
ss.deleteSheet(shts[i]); //I think this is just deleting the sheet and not the array element in shts so no reason to keep track of deleted sheets like when deleting rows in a spreadsheet
}
}
for(var i = 0; i<hdnShts.length; i++) {
ss.getSheetByName(hdnShts[i]).hideSheet(); //just to make sure all the hiddens remain hidden
}
}
I've been forcing myself to get away from old school loops.
function delSheetsKeepHidden() {
var ss=SpreadsheetApp.getActive();
var shts=ss.getSheets();
var hdnShts=[];
shts.forEach(function(sht){if(sht.isSheetHidden()){hdnShts.push(sht.getName())}});
shts.forEach(function(sht){if(sht.getName().slice(0,5).toLowerCase()=="sheet"){ss.deleteSheet(sht);}});//I think this is just deleting the sheet and not the array element in shts so no reason to keep track of deleted sheets like when deleting rows in a spreadsheet
hdnShts.forEach(function(name){ss.getSheetByName(name).hideSheet();});//just to make sure all the hiddens remain hidden
}
Related
I am trying to get this function to work in Apps Script but for the life of me I cant seem to find the problem.
I have a range of cells highlighted in one column in my sheet. I want to delete all the contents from those cells - not the rows.
Here is what I have so far:
function clearGreen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getDataRange();
var bgColors = range.getBackgrounds();
for (var i=0; i<bgColors.length; i++) {
for (var j=0; j<bgColors[i].length; j++) {
if (bgColors[i][j] === '#D9E9D3') {
range.getCell(i+1,j+1).clearContent();
}
}
}
}
The error it is returning when trying to debug is as follows:
TypeError: Cannot read property 'getSheets' of null
clearGreen # Code.gs:4
UPDATE: The below solution worked perfectly and much faster than my code. NOTE your worksheet needs to be the FIRST worksheet in your workbook, mine was sheet 59 so once I moved it to the first position it executed perfectly.
THANK YOU!
Try to change the line:
if (bgColors[i][j] === '#D9E9D3') {
with:
if (bgColors[i][j].toUpperCase() === '#D9E9D3') {
And it will work much faster this way:
function clearGreen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getDataRange();
var bgColors = range.getBackgrounds();
var data = range.getValues() // <--- get all the data as an array
for (var i=0; i<bgColors.length; i++) {
for (var j=0; j<bgColors[i].length; j++) {
if (bgColors[i][j].toUpperCase() === '#D9E9D3') {
data[i][j] = ''; // <--- change the array
}
}
}
range.setValues(data); // <--- put the array back on the sheet
}
For the life of me I can't figure out how set it up. I would like the function to check the entire sheet... alternatively I do know which specific ranges (B5:B26; G5:G26...AF5:AF26) on a specific sheet, if i can't set it up for the entire sheet...
function setFalse()
{
var sheet = SpreadsheetApp.getSheetByName("Test");
var dataRange = sheet.getRange('A:AN28');
var values = dataRange.getValues();
for (var i = 0; i < values.length; i++)
{
for (var j = 0; j < values[i].length; j++)
{
if (values[i][j] == true)
{
values[i][j] = false; // Modified
}
}
}
dataRange.setValues(values);
};
There's a built-in method to uncheck called uncheck(). You can effectively apply it to the sheet by using getDataRange().
function setFalse() {
SpreadsheetApp.getActive().getSheetByName("Test").getDataRange().uncheck();
};
Lastly, looking at your original code, don't forget to get a spreadsheet file before selecting the sheet.
I have a custom function using DeveloperMetadata from other sheets in the workbook. The issue I have is that if I e.g. delete one of previous sheets (thus removing that metadata) the cell value doesn't change. The only trigger which recalculates this function is to make a simple whitespace change in the Script Editor and save the file.
Is there a method in Google Sheets to do this refresh automatically?
function get_prev_days(rest_key) {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheets = spreadsheet.getSheets();
var sheet_index = SpreadsheetApp.getActiveSheet().getIndex();
var value = 0;
for (var i = 0; i < sheet_index; i++) {
var meta = sheets[i].getDeveloperMetadata();
for (var j = 0; j < meta.length; j++) {
if (rest_key == meta[j].getKey()) {
value += Number(meta[j].getValue());
}
}
}
return value;
}
I wrote a script to automatically generate charts from data on different tabs (after clicking a button on a new sheet).
I would now like to add a "reset" button which will automatically delete or remove the generated charts (so I can generate different charts with another button).
Can anyone help on how I can do this? I've tried the below, but to no avail....
function Finance_clear() {
function deleteAllChartsFromSheet(sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var chartsSheet = ss.getSheetByName(sheetName);
var n = chartsSheet.getCharts().length;
for (var i = n-1; i >= 0; i--) {
var chart = chartsSheet.getCharts()[i];
chartsSheet.removeChart(chart);
}
}
};
Delete All Charts from a Sheet
function delAllChartsFromSheet(name) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName(name);
var chts=sh.getCharts();
for(var i=0;i<chts.length;i++){
sh.removeChart(chts[i]);
}
}
Sheet Reference
The code worked for me, I rewrote it as:
function remove_charts_from_sheet(sheet_name) {
const tab = SpreadsheetApp.getActive().getSheetByName(sheet_name);
const charts = tab.getCharts();
for(let i = 0; i < charts.length; i++){
tab.removeChart(charts[i]);
}
}
I've written gs script to clear data from all cells in sheets. Spreadsheet has a lot of sheets (about 200) and I get error of time limit execution. Maybe somebody have ideas how to resolve this issue. Here example of my code.
function cleanAllOld() {
var sheetsName = new Array();
var destination = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/link");
var sheets = destination.getSheets();
for (var k = 0; k < sheets.length; k++) {
sheetsName.push([sheets[k].getName()]);
for (var p = 0; p < sheetsName.length; p++) {
var sheet = destination.getSheetByName(sheetsName[p]);
if (sheet === null) {} else {
sheet.getDataRange().clearContent();
}
}
}
}
I don't get all the part of your code, but I think he's too complicated for nothing. Here's is a sample which work:
function AllDelete() {
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/link");
var sheets = ss.getSheets();
var i = 0;
for(i in sheets){
sheets[i].clearContents();
}
}
Edit: Max is fast and is right, the getDataRange() method is using a lot of ressources
I think the problem is geting data range.
Try replace this
sheet.getDataRange().clearContent();
by this:
sheet.clearContents();