All:
I am new... very new to coding, so I apologize that my coding probably makes people cringe. I have a script that will show and hide sheets depending on the value of cells on a sheet called "Teacher Information." The script is working great except it is running any time an edit is made to ANY of the sheets in the file. I only want it to run if a change is made to the "Teacher Information" sheet. Please advise. Thank you for sharing your expertise. Here is my current code:
function HideSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Teacher Information");
var sheet2 = ss.getSheetByName("SGO1 Plan");
var sheet3 = ss.getSheetByName("SGO1 Data");
var sheet4 = ss.getSheetByName("SGO1 Report");
var sheet5 = ss.getSheetByName("SGO2 Plan");
var sheet6 = ss.getSheetByName("SGO2 Data");
var sheet7 = ss.getSheetByName("SGO2 Report");
var sheet8 = ss.getSheetByName("SGO 1 Plan");
var sheet9 = ss.getSheetByName("SGO 1 Data");
var sheet10 = ss.getSheetByName("SGO 1 Report");
var sheet11 = ss.getSheetByName("SGO 2 Plan");
var sheet12 = ss.getSheetByName("SGO 2 Data");
var sheet13 = ss.getSheetByName("SGO 2 Report");
var cell1 = sheet1.getRange('C22');
var cell2 = sheet1.getRange('AJ22');
if (cell1.getValue() == "") {
sheet2.showSheet();
sheet3.showSheet();
sheet8.showSheet();
sheet9.showSheet();
}
if (cell1.getValue() == "0") {
sheet2.hideSheet();
sheet3.hideSheet();
sheet8.hideSheet();
sheet9.hideSheet();
}
if (cell1.getValue() == "1") {
sheet2.showSheet();
sheet3.showSheet();
sheet8.hideSheet();
sheet9.hideSheet();
}
if (cell1.getValue() == "2") {
sheet2.hideSheet();
sheet3.hideSheet();
sheet8.showSheet();
sheet9.showSheet();
}
if (cell2.getValue() == "") {
sheet5.showSheet();
sheet6.showSheet();
sheet11.showSheet();
sheet12.showSheet();
}
if (cell2.getValue() == "0") {
sheet5.hideSheet();
sheet6.hideSheet();
sheet11.hideSheet();
sheet12.hideSheet();
}
if (cell2.getValue() == "1") {
sheet5.showSheet();
sheet6.showSheet();
sheet11.hideSheet();
sheet12.hideSheet();
}
if (cell2.getValue() == "2") {
sheet5.hideSheet();
sheet6.hideSheet();
sheet11.showSheet();
sheet12.showSheet();
}
}
You can check the sheet name and proceed depending on that.
Something like this :
function HideSheets(e) {
if (e.range.getSheet().getName() != "Teacher Information") {
// If the sheet name is not equal to "Teacher Information" then Back Off..!!
return
}
// Put your other codes below
// More codes
}
This will check the sheet name before proceeding and if it's not equal to "Teacher Information" then it will return/break and not execute the code following it
Reference and further read : https://developers.google.com/apps-script/guides/triggers/events#edit (as per techhowch comment, credits to him)
You don't say if this is an On edit trigger which could be done slightly differently but you could also do this.
var ss = SpreadsheetApp.getActiveSpreadsheet();
if( ss.getActiveSheet().getName() !== "Teacher Information" ) return;
Related
looking for a help to fix my script in Google spreadsheets.
I want to build a function that sends an email every time a certain cell in the list is updated.
Here is my code, but it doesn't work.
Looking for your help to find and fix my issue
function onEdit(e) {
const specificSheet = "Inventory"
const specificCell = "B1"
let sheetCheck = (e.range.getSheet().getName() == specificSheet)
let cellCheck = (e.range.getA1Notation() == specificCell)
if (!(sheetCheck && cellCheck)) {
return
}
else {
sendEmail(){
var subject = "New update";
var emailAddress = "example#gmail.com";
var message = "new update: link";
MailApp.sendEmail(emailAddress, subject, message)
}
}
}
Send email on an Edit
function onMyEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() = "Inventory" && e.range.columnStart == 2 && e.range.rowStart == 1) {
var subject = "New update";
var emailAddress = "example#gmail.com";
var message = "new update: link";
MailApp.sendEmail(emailAddress, subject, message)
}
}
I think this needs to be an installable trigger in order to send an email.
Sometimes Sheet can not process complex operations related to onEdit(e), so maybe this could help:
function onEdit(e) {
const specificSheet = "Inventory";
const specificCell = "B1";
var range = e.range;
var ss = e.source;
var sheetName = ss.getActiveSheet().getName();
var a1Notation = range.getA1Notation();
if ((sheetName==specificSheet) && (a1Notation==specificCell)) {
var props = PropertiesService.getScriptProperties();
props.setProperty("CHECKED","TRUE");
}
}
function sendEmail(){
var subject = "New update";
var emailAddress = "example#gmail.com";
var message = "new update: link";
var props = PropertiesService.getScriptProperties();
var checked = props.getProperty("CHECKED");
if (checked == "TRUE"){
GmailApp.sendEmail(emailAddress, subject, message);
Utilities.sleep(3000);
props.setProperty("CHECKED","FALSE");
}
}
Another thing you should do is setting sendEmail() function is activated by time trigger every minute or so...
I don't know much about programming but I created a script for one of my spreadsheets which worked very well a few months ago.
But lately it is impracticable to use any script, however simple it may be. Sometimes it runs perfectly in 1 or 2 seconds and most of the time it just times out and fails. 90% of executions result in "timed out".
In summary, the function must be executed every time column B or C of the spreadsheet is edited. For this I used the function OnEdit ().
When column B is edited, the date and time is inserted in column D in the respective line where the change occurred.
When column C is edited, the date and time is inserted in column E in the respective line where the change occurred.
Here is the code:
function onEdit(e)
{
var column = e.range.getColumn();
var aba = e.source.getActiveSheet().getName();
if (column == 2 && aba == "Controle")
{
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
if(cell.getValue() != "")
{
var add = cell.offset(0, 2);
var data = new Date();
data = Utilities.formatDate(data, "GMT-03:00","dd/MM/yyyy' 'HH:mm' '");
add.setValue(data);
}
else
{
var add = cell.offset(0, 2);
var data = new Date();
data = "";
add.setValue(data);
}
}
if (column == 3 && aba == "Controle")
{
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
if(cell.getValue() == true)
{
var add = cell.offset(0, 2);
var data = new Date();
data = Utilities.formatDate(data, "GMT-03:00","dd/MM/yyyy' 'HH:mm' '");
add.setValue(data);
}
else
{
var add = cell.offset(0, 2);
var data = new Date();
data = "";
add.setValue(data);
}
}
}
Even super simple recorded macros like applying a filter are showing this problem.
I would like to know if there is something that can be done in the code to make it more efficient to solve this problem or if the timeout problem reached is related to something else.
Thanks
Try this:
function onEdit(e) {
const sh=e.range.getSheet();
if(sh.getName()=='Controle' && e.range.columnStart>1 && e.range.columnStart<4) {
if(e.range.columnStart==2) {
if(e.value='') {
e.range.offset(0,2).setValue(Utilities.formatDate(new Date(), "GMT-3", "dd/MM/yyyy' 'HH:mm' '"));
}else{
e.range.offset(0,2).setValue(new Date());
}
}
if(e.range.columnStart==3) {
if(e.value==true) {
e.range.offset(0,2).setValue(Utilities.formatDate(new Date(), "GMT-3", "dd/MM/yyyy' 'HH:mm' '"));
}else{
e.range.offset(0,2).setValue(new Date());
}
}
}
}
Based on your logs, your script is reaching quota for exceeding maximum execution time, although it is also possible from your scenario to have more than 30 simultaneous executions, which will make the script fail to run too.
One workaround, as Cooper have said in the comments, is to implement a lock on parts of the script, especially on sections that make changes to the spreadsheet, to make subsequent executions wait on one script to complete.
Sample code:
function onEdit(e)
{
var column = e.range.getColumn();
var aba = e.source.getActiveSheet().getName();
var lock = LockService.getScriptLock();
try { lock.waitLock(10000); } // wait 10 sec
if (column == 2 && aba == "Controle")
{
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
if(cell.getValue() != "")
{
var add = cell.offset(0, 2);
var data = new Date();
data = Utilities.formatDate(data, "GMT-03:00","dd/MM/yyyy' 'HH:mm' '");
add.setValue(data);
}
else
{
var add = cell.offset(0, 2);
var data = new Date();
data = "";
add.setValue(data);
}
}
if (column == 3 && aba == "Controle")
{
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
if(cell.getValue() == true)
{
var add = cell.offset(0, 2);
var data = new Date();
data = Utilities.formatDate(data, "GMT-03:00","dd/MM/yyyy' 'HH:mm' '");
add.setValue(data);
}
else
{
var add = cell.offset(0, 2);
var data = new Date();
data = "";
add.setValue(data);
}
}
SpreadsheetApp.flush(); // applies all pending spreadsheet changes
lock.releaseLock();
}
References:
Quotas for Google Services
Class Lock
I have a Sheet which only columns A-C I want to share with user1, and only columns F-H to user2. I do this work with Apps Script. Neither user1 nor user2 are the owner. To execute some code I have to delete all the protection for all users. I wrote the code below for this, but it only works for the owner and not for other users.
function onOpen (e){
var s1 = SpreadsheetApp.getActive();
var range1 = s1.getRange('A:A');
var range2 = s1.getRange('B:J');
var range3 = s1.getRange('K:Z');
var range4 = s1.getRange('AA:AC');
var range5 = s1.getRange('AD:AE');
var range6 = s1.getRange('A1:AE1');
var protection1 = range1.protect().setDescription('1');
var protection2 = range2.protect().setDescription('2');
var protection3 = range3.protect().setDescription('3');
var protection4 = range4.protect().setDescription('4');
var protection5 = range5.protect().setDescription('5');
var protection6 = range6.protect().setDescription('6');
protection1.removeEditors(protection1.getEditors());
protection2.removeEditors(protection2.getEditors());
protection3.removeEditors(protection3.getEditors());
protection4.removeEditors(protection4.getEditors());
protection5.removeEditors(protection5.getEditors());
protection6.removeEditors(protection6.getEditors());
protection1.addEditor('rafi#gmail.com');
protection1.addEditor('naseri#gmail.com');
protection2.addEditor('sabeti#gmail.com');
protection2.addEditor('chavoshi#gmail.com');
protection2.addEditor('naseri#gmail.com');
protection3.addEditor('naseri#gmail.com');
protection3.addEditor('rezvani#gmail.com');
protection3.addEditor('nurian#gmail.com');
protection3.addEditor('fazeli#gmail.com');
protection4.addEditor('naseri#gmail.com');
protection5.addEditor('naseri#gmail.com');
protection5.addEditor('nurian#gmail.com');
protection5.addEditor('fazeli#gmail.com');
protection5.addEditor('rezvani#gmail.com');
protection6.addEditor('chavoshi#gmail.com');
protection6.addEditor('naseri#gmail.com');
if (protection1.canDomainEdit()) {
protection1.setDomainEdit(false);
}
if (protection2.canDomainEdit()) {
protection2.setDomainEdit(false);
}
if (protection3.canDomainEdit()) {
protection3.setDomainEdit(false);
}
if (protection4.canDomainEdit()) {
protection4.setDomainEdit(false);
}
if (protection5.canDomainEdit()) {
protection5.setDomainEdit(false);
}
if (protection6.canDomainEdit()) {
protection6.setDomainEdit(false);
}
}
}
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var r = s.getActiveRange();
if(s.getName() == "Order List" && r.getColumn() == 30 && r.getValue() == true) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Arrived Complete");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
var s10 = SpreadsheetApp.getActive();
var protections = s10.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
onOpen (e);
}
function clearFormat() {
var s = SpreadsheetApp.getActiveSpreadsheet();
var ss = s.getActiveSheet();
var sheetname = ss.getName();
var s2c = SpreadsheetApp.getActiveSpreadsheet();
var ss2cc = s2c.getActiveSheet();
var sheetname = ss2cc.getName();
if (sheetname == "Arrived Complete") {
ss.clearConditionalFormatRules();
}
if (sheetname == "Arrived Canceled") {
ss2cc.clearConditionalFormatRules();
}
}
I am afraid that there is no direct way of doing your goal: to show certain parts of a Sheet only to some users. But there is hope to accomplish something similar, because there are two known workarounds for that:
One way is to publish a webapp that checks the username (like you did in your code) and prints only the intended column.
Another way is to share different Sheets with different users, with only the data that you want to show them. Each Sheet will be automatically synchronized with a master sheet that joins all of them together; but only the administrator will access it.
As you can see, these are two close workarounds. I hope that they work for you. Don't hesitate to write back with any question or doubt.
My google sheets document has multiple sheets (tabs). How do I specify the spreadsheet in which code should work?
I am using the last code from the post below to collect the date and user who changes a particular cell, but the code works for all spreadsheets (tabs) in my document.
Is It Possible To Write Username Of Editor To Cell In Google Docs Spreadsheet
I would like it to work on just one spreadsheet: "Test"
I tried this but to no avail:
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
function getOwnName(){
var email = Session.getActiveUser().getEmail();
//Browser.msgBox("getOwnName");
//var self = ContactsApp.getContact(email);
var self = false;
// If user has themselves in their contacts, return their name
if (self) {
// Prefer given name, if that's available
var name = self.getGivenName();
// But we will settle for the full name
if (!name)
{
name = self.getFullName();
}
//Browser.msgBox(name);
return name;
}
// If they don't have themselves in Contacts, return the bald userName.
else {
var userName = Session.getActiveUser().getEmail();
//Browser.msgBox(userName);
return userName;
}
}
function onEdit() {
var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
var r = s.getActiveCell();
if( r.getColumn() == 14 ) //checks the column
{
var nextCell = r.offset(0, 1);
nextCell.setValue(new Date());
//Browser.msgBox("hey!");
//s.setActiveSelection(p + "15");
//show();
//SpecialonOpen();
var nCell = r.offset(0,2);
//Browser.msgBox("olah:" + getOwnName());
nCell.setValue(getOwnName());
}
}
The active cell is the one that is being edited, no matter what the sheet is.
If you want to stick to getActiveCell(), you need to implement an if statement verifying if you are in the right sheet:
function onEdit() {
if(SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName()=="Test")
{
var s = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var r = s.getActiveCell();
if( r.getColumn() == 14 ) //checks the column
{
...
A different elegant solution would be to work with e.range:
function onEdit(e) {
if(SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName()=="Test")
{
var r = e.range;
if( r.getColumn() == 14 ) //checks the column
{
...
I have a Google Sheets shared with others. My sheet name is "OrderList". I am looking for a script that grabs the user's email address and inputs into another cell when a user edits the sheet. I have written the following code, however it only returns the sheet owner's Gmail address:
var COLUMNTOCHECK1 = 5;
var COLUMNTOCHECK2 = 6;
var DATETIMELOCATION1 = [0,2];
var DATETIMELOCATION2 = [0,3];
var SHEETNAME = 'OrderList'
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if( sheet.getSheetName() == SHEETNAME ) {
var selectedCell = ss.getActiveCell();
if( selectedCell.getColumn() == COLUMNTOCHECK1) {
var email = Session.getActiveUser().getEmail();
var dateTimeCell =
selectedCell.offset(DATETIMELOCATION1[0],DATETIMELOCATION1[1]);
dateTimeCell.setValue(new Date());
var dateTimeCell1 =
selectedCell.offset(DATETIMELOCATION2[0],DATETIMELOCATION2[1]);
dateTimeCell1.setValue(email);
}
if( selectedCell.getColumn() == COLUMNTOCHECK2) {
var dateTimeCell =
selectedCell.offset(DATETIMELOCATION2[0],DATETIMELOCATION2[1]);
dateTimeCell.setValue(new Date());
}
}
}
Since you're running this onEdit(e) you can use Event Objects, these are great for capturing the data you're trying to achieve. You'll need to set up an onEdit trigger for your project to capture the email address though. The code below should achieve what you're expecting.
var COLUMNTOCHECK1 = 5;
var COLUMNTOCHECK2 = 6;
var DATETIMELOCATION1 = [0,2];
var DATETIMELOCATION2 = [0,3];
var SHEETNAME = 'OrderList'
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if( sheet.getSheetName() == SHEETNAME ) {
var selectedCell = ss.getActiveCell();
if( selectedCell.getColumn() == COLUMNTOCHECK1) {
var email = e.user.getEmail();
var dateTimeCell =
selectedCell.offset(DATETIMELOCATION1[0],DATETIMELOCATION1[1]);
dateTimeCell.setValue(new Date());
var dateTimeCell1 =
selectedCell.offset(DATETIMELOCATION2[0],DATETIMELOCATION2[1]);
dateTimeCell1.setValue(email);
}
if( selectedCell.getColumn() == COLUMNTOCHECK2) {
var dateTimeCell = selectedCell.offset(DATETIMELOCATION2[0],DATETIMELOCATION2[1]);
dateTimeCell.setValue(new Date());
}
}
}
As you can see, I've change your var email to use an event object to capture the email address of the user that is editing the spreadsheet:
var email = e.user.getEmail();