Add or remove editors in 1st protection in multiple sheets - javascript

good day! I have several sheets with 1 protection each, and I want to loop among these sheets and add or remove editors in their protections.
Initially, I have this code:
function AddOrRemove() {
var spreadsheet = SpreadsheetApp.getActive();
var allProtections = spreadsheet.getActiveSheet().getProtections(SpreadsheetApp.ProtectionType.SHEET);
var protection = allProtections[0];
protection.removeEditors(['email1#gmail.com']);
protection.addEditors(['email2#gmail.com']);
};
This removes email1#gmail.com while adds email2#gmail.com on the ActiveSheet, meaning I have to manually go to each sheet and run it from there. However, I want to automate the looping of sheets, and thus came up with this code:
function AddOrRemove() {
var sheets = ["Sheet1","Sheet2","Sheet3","Sheet4","Sheet5","Sheet6","Sheet7","Sheet8","Sheet9","Sheet10"];
for (var i = 0 ; i = 15 ; i++){
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheets[i]);
var allProtections = spreadsheet.getProtections(SpreadsheetApp.ProtectionType.SHEET);
var protection = allProtections[0];
protection.removeEditors(['email1#gmail.com']);
protection.addEditors(['email2#gmail.com']);
}
};
where sheets are all the sheet names I wan to run the code to. However, when trying to run it, I encounter this error:
TypeError: Cannot call method "getProtections" of null. (line 5, file "AddOrRemoveEditors")
I tried Logger.log(sheets[i]); just before the var Spreadsheets in the for loop, and it's logging "null". However, when I put Logger.log(sheets[0]); before the for loop, it's correctly returning K. I'm not quite sure what's missing here. I feel the logic behind the code should work, but maybe I'm missing something. Asking for advise on this. Thanks!

try this:
function AddOrRemove() {
var sheets = ["Sheet1","Sheet2","Sheet3","Sheet4","Sheet5","Sheet6","Sheet7","Sheet8","Sheet9","Sheet10"];
for (var i=0;i<sheets.length;i++){//modified
var spreadsheet = SpreadsheetApp.getActive().getSheetByName(sheets[i]);//modified
var allProtections = spreadsheet.getProtections(SpreadsheetApp.ProtectionType.SHEET);
var protection = allProtections[0];
protection.removeEditors(['email1#gmail.com']);
protection.addEditors(['email2#gmail.com']);
}
};

Related

Hide a sheet when I am active on another sheet

I am trying to automatically hide a sheet called "Add expense" when I am not active on it.
For example.
I have the sheet "BD Expenses", the sheet "BD Tokens", the sheet "BD Income", the sheet "Add expense", the sheet "Add income".
What I want is that when I am active in any of the sheets that is not called "Enter expense", then the script runs completely automatically (without having to click on any button) to hide the sheet called "Add expense".
I currently have this code:
//Ocultar todas las hojas excepto la activa
function Ocultar_formulario_ANADIR_GASTO() {
var sheets = SpreadsheetApp.getActiveSheet();
sheets.forEach(function(sheet) {
if (sheet.getSheetByName('Añadir gasto') != SpreadsheetApp.getActiveSheet().getName())
sheet.hideSheet();
});
};
I have tried various methods but without success.
I know there is a function called onSelectionChange (e) but since I am so new to Javascript I don't really know how to make it work. Hence I have created my code differently.
I have looked at the reference from https://developers.google.com/apps-script/reference/spreadsheet/sheet#hidesheet
I've also googled and stackoverflow, but can't find a solution to this problem.
Currently when running the script from the editor, I get the error "TypeError: sheets.forEach is not a function".
I can't get it to work.
I would really appreciate if someone can take a look at my code and offer me a little help.
Thank you very much.
It looks like there is no specific Google Scripts event for when you change sheets.
But there is a workaround mentioned in the issue tracker ticket - scroll to the bottom of the ticket to see it. It involves using onSelectionChange(e) to track which sheets you moved out of and into.
The following code adapts that workaround to your case:
The code assumes your Google spreadsheet has 2 or more sheets - and one of those sheets is called Secret Sheet. You can change this name to whatever you want (see the first line of the code).
When you move from the Secret Sheet to any other sheet, the Secret Sheet will automatically be hidden.
var secretSheetName = 'Secret Sheet'; // change this to whatever you prefer.
var prevSheetProperty = 'PREVIOUS_SHEET';
function saveActiveSheet() {
var activesheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty(prevSheetProperty, activesheet.getSheetName());
}
function onSheetChange(e) {
var sheetToHide = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(secretSheetName);
sheetToHide.hideSheet();
}
function onSelectionChange(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get current sheet name and compare to previously saved sheet
var currentSheetName = ss.getActiveSheet().getSheetName();
var userProperties = PropertiesService.getUserProperties();
var previousSheetName = userProperties.getProperty(prevSheetProperty);
if (currentSheetName !== previousSheetName) {
saveActiveSheet(); // this becomes the new "previous sheet".
if (previousSheetName === secretSheetName) {
// you have moved out of the secret sheet - so, hide it:
onSheetChange(e); // Call custom sheet change trigger
}
}
}
function onOpen(e) {
saveActiveSheet();
}
The script works by keeping track of which sheet is the currently active sheet - and which was the (different) previously active sheet before that.
It stores the "previous" sheet name in a user property.
You will see that to use the onSelectionChange(e) event, you simply have to add that function to your script:
function onSelectionChange(e) { ... }
Google Scripts automatically recognizes this as an event function. You can read more about this, with examples, here.
I am going to reply to my own question to provide the same solution as #andrewjames but for multiple sheets to be hidden at once.
The code to hide a single sheet can be found in #andrewjames comment.
The code to hide multiple sheets using the code of #adrewjames as a base, is this.
var addFicha = 'Añadir ficha'; // change this to whatever you prefer.
var addGasto = 'Añadir gasto'; // change this to whatever you prefer.
var addIngreso = 'Añadir ingreso'; // change this to whatever you prefer.
var hideMultipleSheets = addFicha || addGasto || addIngreso;
var prevSheetProperty = 'PREVIOUS_SHEET';
function saveActiveSheet() {
var activesheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var userProperties = PropertiesService.getUserProperties();
userProperties.setProperty(prevSheetProperty, activesheet.getSheetName());
}
function onSheetChange(e) {
var sheetToHide1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(addFicha);
var sheetToHide2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(addGasto);
var sheetToHide3 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(addIngreso);
sheetToHide1.hideSheet();
sheetToHide2.hideSheet();
sheetToHide3.hideSheet();
}
function onSelectionChange(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get current sheet name and compare to previously saved sheet
var currentSheetName = ss.getActiveSheet().getSheetName();
var userProperties = PropertiesService.getUserProperties();
var previousSheetName = userProperties.getProperty(prevSheetProperty);
if (currentSheetName !== previousSheetName) {
saveActiveSheet(); // this becomes the new "previous sheet".
if (previousSheetName === hideMultipleSheets) {
// you have moved out of the secret sheet - so, hide it:
onSheetChange(e); // Call custom sheet change trigger
}
}
}
function onOpen(e) {
saveActiveSheet();
}
Here I leave a brief explanation so that if someone needs this code they know how to modify it so that it works for their needs.
1. At the beginning of all of the code, we see the first 3 vars.
In this case we want to hide 3 sheets, that's why there are only 3 vars. In case you want to hide 5 sheets, you should have 5 vars.
Here you can name them whatever you want. Then, the text in quotation marks is the name of the sheet you want to hide, so you must change it to the name of your sheets.
Example:
var hideSheettt1 = 'Here you need to copy the name of your sheet';
2. Following the first 3 vars, we have the 4 var hideMultipleSheets
In this case we are joining the first 3 vars into a single var to be able to reuse it later in the onSelectionChange (e) function
Here you must replace addFicha addGasto addIngreso with the name you have given to your first vars.
Continuing with the example from point 1, we will use the var hideSheettt1 = 'Here you need to copy the name of your sheet'; as a reference.
Example:
var hideMultipleSheets = hideSheettt1 || hideSheettt2|| hideSheettt3;
3. In the SheetChange (e) function you must substitute the var of .getSheetByName () in the first 3 vars, by the name of the var that you created at the beginning of the entire code (point 1).
Example:
var sheetToHide1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(hideSheettt1);
At this point, you should include as many vars as sheets you want to hide and vars you have created at the beginning of your code. In this case we want to hide 3 sheets. But if we wanted to hide 5 sheets, we must have 5 vars, one for each sheet.
We must also have the same amount of hideSheet()

how to onFormSubmit(), two separate google source spreadsheets?

I have two google separate forms that submit new client data to two separate spreadsheets. How would I use the onFormSubmit() on two separate spreadsheet sources in one app script editor? thank you all very much :D
if this is getting one sheet how could it implement two or more?
i think i get SpreadsheetApp.getSheetByName('xyz');
and im a little unsure exactly what an active sheet is or activated I think it is the sheet you're currently on in the spreadsheet the dev app script is being derived from. I might be missing some other basic concepts
function onFormSubmit(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sht = ss.getSheetByName('New Client Submission Form (Phone)'&&'New Client Submission Form (Emailed)')
var activeRng = sht.getRange("A2:K2")
var values = activeRng.getValues()
var height = values.length
var width = values[0].length
var ss_dest = SpreadsheetApp.openById('1wgzUSXFNLFQz6tv42Cp_o94qRPAB9IkZnKP5tGL003o')
var sht_dest = ss_dest.getSheetByName('Estimate Compiler')
var destRange = sht_dest.getRange(2,1,height,width)
destRange.setValues(values)
}
this function does exatly as expected I just don't know how to implement two or more yet
function onFormSubmit(e) {
var formObj={LinkedSheet1:FormName1,LinkedSheet2:FormName2};//you provide this from a knowledge of the connection between the form and linked sheet
var form=formObj[e.range.getSheet().getName()];//this returns the form for each sheet
switch (form) {
case 'FormName1':
//code for FormName1
break;
case 'FormName2':
//code for FormName2
break;
}
}
onFormSubmit Event Object

is it possible? onChange from one spreadsheet triggers onChange from another spreadsheet

I have a sheet that when the onchange triggers it makes a mirror of the information to use as a reference later when it determine which rows changed. I had this connected to a Query function. Whenever the query got updated, the onChange function would run. But sometimes the query would act weird and information would appear blank on the sheet it copies to even though i can see it on the query. And if two computers were looking at the query at the same time, it was evident that it didn't update on all screens. So i decided, why not, instead of a query, we have the information get updated the same way the mirror is updated. So it copies all the information down and puts it onto the sheet, no query needed. I figured this would at least make sure everyone is seeing the same information. So i made a query sheet, and added an onChange() trigger to it that grabbed all the info and pasted it onto the main sheet, whenever the query updated. (even if it messes up, at least it's much more obvious and no one is seeing anything different). But when the information was posted onto the main spreadsheet. THAT spreadsheet's onChange function didn't trigger. I thought it would trigger whenever there was a change. No matter what. So I then decided to create a new function in the Query Sheet where it inserts and deletes the last row, even say hi, thinking if I make the sheet change more prominently, the onChange() function would trigger. Still didn't. I'm at a loss.
function onChangeMirror() {
var sos = SpreadsheetApp.openById("the sheet with the query");
var sas = SpreadsheetApp.setActiveSpreadsheet(sos);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s1 = ss.getActiveSheet();
var lastRow = s1.getLastRow();
var lastRow1 = s1.getLastRow()+1;
var lastRow10 = s1.getLastRow() +10;
var SRange = s1.getRange(2,1,lastRow,2);
var A1Range = SRange.getA1Notation();
var SData = SRange.getValues();
var sos2 = SpreadsheetApp.openById("the sheet it's updating");
var sas2 = SpreadsheetApp.setActiveSpreadsheet(sos2);
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var s2 = ss2.getActiveSheet();
var MaxRow = s2.getMaxRows();
s2.getRange(A1Range).setValues(SData);
Logger.log(lastRow1)
Logger.log(lastRow10)
s2.getRange('A'+ lastRow1+':'+'B'+lastRow10).setValue(null);
Logger.log(A1Range)
if(MaxRow > '300') {
s2.deleteRow(MaxRow)
}
else if(MaxRow < '301'){
s2.insertRowAfter(MaxRow)
s2.getRange('A'+(MaxRow+1)).setValue('HI')
}
}
here is the script i was using

Google Apps Scripts - Extract data from gmail into a spreadsheet

this is the first script i try to write from scratch. It's been no good up to now so i'm going to ask for some help.
Case: I recieve e-commerce confirmation emails from e-commerce sites no reply email address. In the email's body they send email address from buyers. I want to send an automated mail to the body's email address.
How i plan to do this (any suggetions to eliminate steps will be thanked).
Use a rule to tag incoming emails with a unique tag.
Use that tag to identify emails in gmail with a script, go one by one and extract the info i need. Use regex with the emails body content to extract the email address i need to send the automated emails. Plan is to get: subject, date, email from body.
Write all that info to a spreadsheet.
Get rid of unique tag info to prevent duplicate runs.
Then use form mule addon to send emails from the spreadsheet.
So far, i've dealt with steps 1 (easy), and been stuggling with steps 2 and 3 (im not a coder, i can read, undestrand and hack. writing from scratch is a completely different thing). Ive dealt with 4 before i think this is the best way to deal with it.
With the script i extract info to the spreadsheet, with the addon i use the info from the spreadsheet to send emails.
This is the code ive written so far. I've left the regex part for later cause i cant even write anything into the spreadsheet yet. once i get that working, ill start working in the regex and "remove the label" aspects of the script.
function myFunction() {
function getemails() {
var label = GmailApp.getUserLabelByName("Main tag/subtag");
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++) {
var messages=threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
var message=messages[j];
var subject=message.getSubject();
tosp(message);
}
}
}
function tosp(message){
var body=message.getBody()
var date=message.getDate();
var subject=message.getSubject();
var id= "my spreasheet id";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getActiveSheet();
sheet.appendRow(subject,date,body);
}
}
Any help would be appreciated.
Thanks
Sebastian
Following is the code I wrote and tested that performs the steps 2, 3 and 4 mentioned by you perfectly well.
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
var label = GmailApp.getUserLabelByName("MyLabel");
var threads = label.getThreads();
for (var i=0; i<threads.length; i++)
{
var messages = threads[i].getMessages();
for (var j=0; j<messages.length; j++)
{
var msg = messages[j].getBody();
var sub = messages[j].getSubject();
var dat = messages[j].getDate();
ss.appendRow([msg, sub, dat])
}
threads[i].removeLabel(label);
}
}
One of the faults in your code was that the appendRow function accepts an array of elements specified within [ ] brackets.
Depending on where you're attaching this script, your line of code:
var ss = SpreadsheetApp.openById(id);
is not necessary if the script is being written in the script editor of the Spreadsheet where you want these emails to be logged. However, if there are multiple sheets in that spreadsheet, you can replace my line
var ss = SpreadsheetApp.getActiveSheet();
by
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
Another suggestion is that the current code will give you messages in HTML format. Hence, if you want to get the message in plain text as you see it, use:
var msg = messages[i].getPlainBody();
Now you can write another function for regex and pass the message msg to that. Hope this helps!
I made a ready-to-use script, explaining how to use it (from the start) as well, for those who need more assistance.
It's on gmail-to-google-sheets-script repository. Just read the content and follow the instructions.
How to use
Create a new Google Sheet
Access menu Tools > Script Editor
Copy the content from gmailt-to-sheets.gs to editor, replacing the sample code there
Replace the value on SEARCH_QUERY to your real query (Do your search on gmail first, copy and paste the search terms there)
Select saveEmails on menu (near "run" and "debug" buttons)
Click on "Run" button
It will ask for authorization at first run, proceed accepting it (it's your Gmail account authorizing your Google Script account)
After run, the results will be applied to you sheet
Changing fields
If you want to save different message attributes, take a look at gmail-message class and change your script file the code below comments with a ✏️ (pencil).

Accessing spreadsheet in Google Script

I am writing a google script on top of a spreadsheet.
I want to deploy it as a web app.
It shows some values.
Unfortunately, with my current code, google reminds me:
TypeError: Cannot call method "getSheetByName" of null.
I have no idea where the mistake is.
Here's the code
function doGet(e) {
var app = UiApp.createApplication().setTitle('Details');
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var dataFromCell = ss.getRange("B4").getValue();
var mypanel = app.createVerticalPanel();
var label = app.createLabel(dataFromCell);
app.add(mypanel);
app.add(label);
return app;
}
In standalone webapps you cannot use getActiveSpreadsheet because no one is using it actively...
Use SpreadsheetApp.openById('ID') instead, you can get the ID in the url of your spreadsheet like in this example :
https://docs.google.com/spreadsheet/ccc?key=0AnqSFd3iikE3d-------nZIV0JQQ0c1a3dWX1dQbGc#gid=0
between key= and #, ie 0AnqSFd3iikE3d-------nZIV0JQQ0c1a3dWX1dQbGc
Not need to use ID , just try this code ( change mygooglelocation with your Spreadsheet name and range of cells. Working very well for me with google maps...
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('mygooglelocation');
var ss = SpreadsheetApp.getActive();
var mylocationInfo = ss.getRange("A2:B4").getValues();

Categories

Resources