Delete all Sheets except one, loop within a loop - google-apps-script

I have a spreadsheet that contains a list of URLS for spreadsheets and the sheet name that I want to keep.
The idea is that I delete all sheets within each of those spreadsheets except the sheet I want to keep.
I have written a script but I can not seem to get it to work, I get an error message of "invalid argument line 20" but I can not figure out why.
I have pasted my code below, any help would be appreciated.
function DeleteImportedData(){
var s3 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("URL's")
var s1 = SpreadsheetApp.getActiveSpreadsheet()
var sh1 = s1.getSheetByName("MasterSheet")
var copy = sh1.getRange(1,1,sh1.getLastRow(),sh1.getLastColumn()).getValues()
var getHeader = sh1.getRange(1,1,1,25).getValues()
for (var j = 1;j<s3.getLastRow(); j++){
var filterName = s3.getRange(j+1, 1).getValue()
var id = s3.getRange(j+1,2).getValue()
var open = SpreadsheetApp.openById(id)
var sheet = open.getSheets()[0];
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sh3 = open.getSheetByName("STSOR - "+filterName)
}
for (i = 0; i <= sheets.length; i++) {
switch(sheets[i]) {
case sheet.getSheetName() === sh3:
break;
default:
open.setActiveSheet(sheet[i]);
open.deleteActiveSheet;
open.deleteSheet(del)
}
}
}

when you delete the first sheet from the list Sheet1, Sheet2, Sheet3 - Sheet2 changes its index to Sheet1. So it is better to delete sheets from the end
try to use the reverse loop
for (i = sheets.length-1; i >=0 ; i--){
... your code ...
}

There is something wrong between your variable sheet and sheets and your second loop.
Try this way :
for (var j = 1;j<s3.getLastRow(); j++){
// your code
// second loop inside the first loop
for (i = 0; i <= sheets.length; i++) {
switch(sheets[i]) {
case sheets[i].getSheetName() === sh3: //instead of 'sheet'
break;
default:
open.setActiveSheet(sheets[i]); //instead of 'sheet'
open.deleteActiveSheet;
open.deleteSheet(del)
}
} // close first loop
} // close second loop
but I think the second loop would be cleaner that way (IMHO):
for (i = 0; i <= sheets.length; i++) {
if (sheets[i].getSheetName() !== sh3) {
open.deleteSheet(sheets[i].getSheetName());
}
}
If this code doesn't answer your question, please provide more informations about your spreadsheets

Related

Google script to copy a newly added row from one sheet and append to another only if it doesn't exist in the second sheet

I have a google sheet (Sheet 1) which gets auto-populated by a script. Now I want to copy the newly added rows to Sheet 2 only if doesn't exist in Sheet 2. I am trying to match column 1 from both the sheets and if it doesnt exist in sheet 2, the row should be appended in sheet 2. I do not have much experience in google script. Here is my code.
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Original');
var s2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Filtered');
var values1 = s1.getDataRange().getValues();
var values2 = s2.getDataRange().getValues();
var resultArray = [];
for(var n=0; n < values1.length ; n++)
{
var keep = false;
var counter = 0;
for(var p=0; p < values2.length ; p++)
{
if( values1[n][1] == values2[p][1])
{
keep = true;
break ;
}
}
if(keep == false)
{
resultArray.push(values1[n]);
s2.appendRow();
resultArray = [];
keep = false
}
}
}
You need to pass an argument to appendRow function. You currently append nothing. See here for an example.
var aRow = ["col1", "col2", "col3"];
SpreadsheetApp.getActiveSheet().appendRow( aRow );
On your end, you should have a array which is populated with the values you want to copy for a particular row. If that row does not exist in sheet2, then add it there.
https://developers.google.com/apps-script/reference/spreadsheet/sheet#appendRow(Object)

Unchecking Checkboxes in Google Sheets

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.

Hard sittuation : how to set value "permission of user" into google sheets correctly?

I have "script A" that can list of any file in "source folder" with url
Then i write "script B" to scan all ID of them and get every email user of file's permission, but when i set "email" value to [i] rows, it will overwrite till the last user of that permission.
Examples: if file "A" has 3 users of view, a#gmail, b#gmail, c#gmail, then "script B" will overwrite till c#gmail at file "A" row. (then we dont know about a#gmail, b#gmail have viewer permission.)
function Listpermission() {
var ss = SpreadsheetApp.getActiveSheet();
var dataLength = getDataLength(); var data = getSheetValues();
for(var i = 0; i < dataLength; i++) {
if(data[i]["Condition"] != "1") continue
var thisid = SpreadsheetApp.getActiveSheet().getRange(i+1, 12).getValue()
Logger.log(thisid)
var editors = DriveApp.getFileById(thisid).getEditors()
for (var x = 0; x < editors.length;x++){
var edit = editors[x].getEmail() }
SpreadsheetApp.getActiveSheet().getRange(i+1, 14).setValue(edit)
var viewers = DriveApp.getFileById(thisid).getViewers()
for (var x = 0; x < viewers.length;x++) {
var view = viewers[x].getEmail()
Logger.log(view)
SpreadsheetApp.getActiveSheet().getRange(i+1, 13).setValue(view)
}}}
This is log of runing script, in the red box, there are 2 user of view but it overwrite at: Range(i+1,13)
Any idea to solve this isue, thank you very much.
You want to retrieve emails of editors and viewers from the file ID.
File IDs are in the column "L".
You want to put the retrieved values to the cells.
From your script, I thought that you might want to put the values of editors and viewers to a cell, respectively.
You want to put the viewers and editors to the column "M" and "N", respectively.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about creating a value using join() and putting the value to the cells? For this situation, how about the following modifications? Please think of this as just one of several answers.
Modified script 1:
Please modify your script as follows. In this modification, the for loop is modified.
function Listpermission() {
var ss = SpreadsheetApp.getActiveSheet();
var dataLength = getDataLength();
var data = getSheetValues();
for(var i = 0; i < dataLength; i++) {
if (data[i]["Condition"] != "1") continue
var thisid = ss.getRange(i+1, 12).getValue()
var editors = DriveApp.getFileById(thisid).getEditors()
var edit = [];
for (var x = 0; x < editors.length;x++) {
edit.push(editors[x].getEmail());
}
ss.getRange(i+1, 14).setValue(edit.join(","));
var viewers = DriveApp.getFileById(thisid).getViewers();
var view = [];
for (var x = 0; x < viewers.length;x++) {
view.push(viewers[x].getEmail());
}
ss.getRange(i+1, 13).setValue(view.join(","));
}
}
Modified script 2:
Please modify your script as follows. In this modification, the values are retrieved by getValues() and are created in the for loop and the created values are put to the Spreadsheet using setValues(). I think that this becomes lower cost of the process than that of getValue() and setValue().
function Listpermission() {
var ss = SpreadsheetApp.getActiveSheet();
var dataLength = getDataLength();
var data = getSheetValues();
var thisids = ss.getRange(1, 12, dataLength, 1).getValues();
var values = [];
for (var i = 0; i < thisids.length; i++) {
if (data[i]["Condition"] != "1") {
values.push(["", ""]);
continue;
}
var thisid = thisids[i][0];
var view = [];
var viewers = DriveApp.getFileById(thisid).getViewers();
for (var x = 0; x < viewers.length;x++) {
view.push(viewers[x].getEmail());
}
var edit = [];
var editors = DriveApp.getFileById(thisid).getEditors();
for (var x = 0; x < editors.length;x++) {
edit.push(editors[x].getEmail());
}
values.push([view.join(","), edit.join(",")]);
}
ss.getRange(1, 13, values.length, 2).setValues(values);
}
References:
join()
getValue()
setValue(value)
getValues()
setValues(values)
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
If I misunderstood your question and this was not the result you want, I apologize.
Fill array with all values to Array and then join all values to one column.
var viewers = DriveApp.getFileById(thisid).getViewers();
var viewerEmails = [];
for (var x = 0; x < viewers.length;x++) {
var view = viewers[x].getEmail();
Logger.log(view);
viewerEmails.push(view);
}
SpreadsheetApp.getActiveSheet().getRange(i+1, 13).setValue(viewerEmails.join());

Google spreadsheets - find all hidden rows - only include rows that are not hidden

The code provided copies data from sheet "Feuille 3" to an another sheet named "INITIALE". Some of the rows in the source sheet tab, "Feuille 3" are hidden.
I hide some rows in "Feuille 3" when col D has a checkbox with a "true" value.
I don't know how I can check the rows hidden in "Feuille 3" and remove these rows in my array "Nouvelleliste."
Here is the code :
function copiertableau() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var orig = ss.getSheetByName("Feuille 3");
var dest = ss.getSheetByName("INITIALE");
var Ancienneliste = orig.getDataRange().getValues();
var Nouvelleliste = new Array();
for (var i = 0; i < Ancienneliste.length; i++) {
var Nouvelleligne = new Array();
for (var j = 0; j < 3; j++) {
Nouvelleligne[j] = Ancienneliste[i][j];
}
Nouvelleliste[i] = Nouvelleligne;
}
ss.getSheetByName("INITIALE").getRange(22, 1, Nouvelleliste.length, 3).setValues(Nouvelleliste);
SpreadsheetApp.flush();
}
The Advanced Sheets API has a way of finding all the rows that were hidden by the user or by code. You must explicitly enable the Advanced Sheets API from the code editor. From the code editor choose, "Resources" and "Advanced Google Services." Scroll down to "Google Sheets API" Turn the button ON. Then click the link to Google API Console. Enable the Google Sheets API in your console.
First get all the rows that are hidden. In the example below, that is done in a separate function. Then compare the current row index to the values in the array. If there is a hidden row, then don't put the row's data into the array.
function copiertableau() {
var arrOfHiddenRows,Nouvelleligne,o,sourceSheetTab,ss;
ss = SpreadsheetApp.getActiveSpreadsheet();
sourceSheetTab = ss.getSheetByName("Feuille 3");
var dest = ss.getSheetByName("INITIALE");
sourceSheetTab = ss.getSheetByName("INITIALE");
var Ancienneliste = sourceSheet.getDataRange().getValues();
var Nouvelleliste = [];
o = {};//Object for arguments to pass to function to get the hidden rows
o.L = sourceSheetTab.getLastRow();
o.ssID = ss.getId();//Put the spreadsheet file ID into the object with key name ssID
o.sheetId = sourceSheetTab.getSheetId();
arrOfHiddenRows = getRowsHiddenByUsr(o);//Get a list of all hidden rows in sheet tab sourceSheet
//Logger.log('arrOfHiddenRows: ' + arrOfHiddenRows)
for (var i = 0; i < Ancienneliste.length; i++) {
if (arrOfHiddenRows.indexOf(i+1) !== -1) {//This row is hidden in the sheet sourceSheet
continue;//continue to loop without putting this rows data into the array
}
Nouvelleligne = [];
for (var j = 0; j < 3; j++) {
Nouvelleligne[j] = Ancienneliste[i][j];
}
Nouvelleliste[i] = Nouvelleligne;
}
ss.getSheetByName("INITIALE").getRange(22, 1, Nouvelleliste.length, 3).setValues(Nouvelleliste);
SpreadsheetApp.flush();
}
function getRowsHiddenByUsr(po) {
try{
var arrHiddenRows,data,fields,i,j,L,L_sh,rows,sheets,sheetId,spreadsheetId,thisSheet,thisShID;
/*
po.L - row length of the sheet tab
po.ssID - the spreadsheet file ID of the spreadsheet
po.sheetID - The ID of the sheet tab
*/
L = po.L;
spreadsheetId = po.ssID;
sheetId = po.sheetID;
//Logger.log(L)
//Logger.log('sheetId: ' + sheetId)
arrHiddenRows = [];
fields = "sheets(data(rowMetadata(hiddenByUser)),properties/sheetId)";//Get only metadata of hidden rows by user
sheets = Sheets.Spreadsheets.get(spreadsheetId, {fields: fields}).sheets;
L_sh = sheets.length;
//Sheets.Spreadsheets.get(spreadsheetId)
//Logger.log('sheets.length: ' + sheets.length)
for (i = 0; i < L_sh; i++) {
thisSheet = sheets[i];
//Logger.log('thisSheet === undefined: ' + thisSheet === undefined)
if (thisSheet === undefined) {
continue;
}
thisShID = thisSheet.properties.sheetId;
//Logger.log('thisShID: ' + thisShID)
if (thisShID === sheetId) {
//Logger.log('they are equal')
data = thisSheet.data;
rows = data[0].rowMetadata;
//Logger.log('thisShID: ' + thisShID)
//Logger.log('rows.length: ' + rows.length)
for (j = 0; j < L; j++) {
//Logger.log(rows[j].hiddenByUser)
if (rows[j].hiddenByUser) arrHiddenRows.push(j+1);
}
}
}
return arrHiddenRows;
}catch(e) {
console.log(e.message);
console.log(e.stack);//log the stack
}
}
thanks #SandyGood It seems it's missing something.
Firstly, i changed
var Ancienneliste = sourceSheet.getDataRange().getValues();
to put "sourceSheetTab" variable; and i delete a line because you put twice "sourceSheetTab" with 2 contents so i keep the first one.
Secondly, your function continue to copy hidden rows in the sourcesheet table.
maybe i can put my other code i did to hide rows in "Feuille 3" to help?
//global variables
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Feuille 3");
function cacherRow() {
for (var i=1; i < 300; i ++){
var nb = sheet.getRange('D'+i).getValue();
if (nb == true){
sheet.hideRows(i);
}
}
}
i enable googlesheets API in the console.
Google Apps Script now offers a new method - isRowHiddenByUser - to determine if a particular row is hidden or not.
for (var i = 0; i < Ancienneliste.length; i++) {
if (sheet.isRowHiddenByUser(i+1)) {
// do something
}
}
Note that you need to specify the row position in the method and it begins from 1, not 0.

Delete Row from all google sheets based on value of a cell

I am trying to achieve a script that will delete a row based upon a string in a cell within that row,
I can achieve my mission if I want to name each individual sheet, however my sheets are constantly changing names, so this would mean updating the the script daily.
I have tried to create a loop, but that does not seem to work either, any suggestions?
The script I am working on is below.
function RemoveInvoiced() {
var ss = SpreadsheetApp.openById("1pxWr3jOYZbcwlFR7igpSWa9BKCa2tTeliE8FwFCRTcQ").getSheets();
for (var k=0; k<ss.length; k++)
var values = ss[k].getDataRange().getValues();
var rows_deleted = 0;
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
var value = values[i][j];
var row = i + 1 - rows_deleted;
if (typeof value === 'string') {
var result = value.search("INVOICED");
if (result !== -1) {
ss.deleteRow(row);
rows_deleted++;
}
}
}
}
};
Instead of using the sheet name to access them, you could access them by Id.
The id will never change as long as you don't delete the sheet, even if you change the name.
You'd first have to get the sheets Id, a simple function could do that for you
function getId(sheet){
Logger.log(sheet.getSheetId());
}
Once you have gotten your sheet ids, you can make a function that will open the right sheet by the ID
function openSheetById(doc, id){
var sheets = doc.getSheets();
for(var i = 0; i< sheets.length ; i++){
if( sheets[i].getSheetId() == id)
return sheets[i];
}
return false;
}
And then you can access the right sheet.
function myFunc(){
var doc = SpreadsheetApp.openById("1pxWr3jOYZbcwlFR7igpSWa9BKCa2tTeliE8FwFCRTcQ");
var id = // your id here
var sheet = openSheetById(doc, id);
if(sheet){
//do other stuffs
}
}