Daily change of the active sheet in the Google Sheets - google-apps-script

Can you please tell me how to automatically change the active sheet in google tables every day with Apps Script, like this: 1-2-3-1-2-3... And hide the inactive ones.
This is needed to show the current dining room menu.

Explanation:
You have three sheets in a spreadsheet file and your goal is to have only one sheet shown at a given day.
The first day you show only the first sheet and you hide the other two. The next day you hide all the sheets except for the second one and the third day you hide all sheets except for the third one.
The fourth day you start over again and you show only the first sheet.
This exercise needs two frameworks to work properly:
You need to store the day counter and the library you can use for that purpose is the PropertiesService class.
You need a time driven trigger to execute the script every day.
Solution:
The only thing you should do is to execute only and once the function createTrigger. The other function in this script is going to be executed every day automatically between 8-9 am and you should not execute it manually.
// execute only and once createTrigger
// Runs myFunction between 8am-9am in the timezone of the script
function createTrigger(){
ScriptApp.newTrigger("myFunction")
.timeBased()
.atHour(8)
.everyDays(1) // runs every day
.create();
}
// this should not be executed manually
function myFunction() {
const spreadsheet = SpreadsheetApp.getActive();
const sheets = spreadsheet.getSheets();
const sp = PropertiesService.getScriptProperties();
const breakPoint = 2; // after third sheet start over
const vs = sp.getProperty("visibleSheet");
let index;
if(vs){
index = parseInt(vs);
}
else {
index = 0;
sp.setProperty("visibleSheet",index);
}
sheets.map(sh=>sh.showSheet());
sheets.forEach((sh,i)=>{
if(i!=index){
sheets[i].hideSheet();
};
});
index==breakPoint ? sp.setProperty("visibleSheet",0)
: sp.setProperty("visibleSheet",index+1);
}
Things you can modify in the script:
Change 8 in atHour(8) if you want to execute the script in a different time rather than 8am.
Change variable breakPoint if you have more sheets (and not only 3). The counter starts from 0 this is why 2 indicates the third sheet. If you have six sheets then change it to breakPoint = 5;. In this way, the code is general and not restricted to the number of sheets.

Solution:
Apart from needing an Installable Trigger to have the script executed daily, this function should rotate the sheets per execution.
Prerequisites:
Take the Sheet ID of your spreadsheet from the URL and replace SHEET-ID in the code: https://docs.google.com/spreadsheets/d/**SHEET-ID**/edit#gid=0
Hide all sheets except one. The active sheet will be the starting point.
// execute this function first
function createTimeDrivenTriggers() {
// Trigger every 24 hours. Set preferred time here:
ScriptApp.newTrigger('myFunction')
.timeBased()
.atHour(10)
.everyHours(24)
.create();
}
// this should not be executed manually
function myFunction() {
var ss = SpreadsheetApp.openById("SHEET-ID");
var sheets = ss.getSheets();
for (var i = 0; i < sheets.length; i++) {
if (!sheets[i].isSheetHidden()) {
sheets[(i+1) % sheets.length].showSheet();
sheets[i].hideSheet();
break;
}
}
}

Related

Google sheet script to shift content once a day

I would like to move the content of B2:F8 to C2:G8 (one column to the right) once a day, at 4am.
How can I achieve that?
Move Stuff one column to the right
function movestuff() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Enter you sheetname");
sh.getRange("B2:F8").moveTo(sh.getRange("C2:G8"));
}
Run the following function once to create the trigger
function createTrigger() {
if(ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == "moveStuff").length == 0) {
ScriptApp.newTrigger("moveStuff").timeBased().everyDays(1).atHour(4).create();
}
}
You can run AppScript triggers to run your custom function once a Day.
For example, you have a function to do this content shifting in your Apps Script.
Then go to your Triggers > Add Trigger > Choose your function to run once in a day > Select the Select event source to Time Driven > Select type of time-based trigger to Day Timer
That's it. It will run a function once a day or you can customize your event whatever you like
From #Cooper solution you can take his code & call it in a daily based event timer.
function contentShifter() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Enter you sheet tab name");
sh.getRange("B2:F8").moveTo(sh.getRange("C2:G8"));
}
Run the function contentShifter in daily event timer that's it. Hope it will help you.

gs - Is it possible to run script even when sheets is closed?

I have a script which uses googlesheets, I am new to this also, there the trigger onOpen() and when the sheet is opened it runs whats inside it, however I wanted to run a function even when sheet is not opened. Do I need a trigger to do this? What should I use to do this?
I tried:
OnCreate
Installable
OnEdit
I want to create a time-based trigger will the script run, even if the sheet is not open and/or even if I'm not logged in to Sheets.
I tried:
function onOpen() {
// Trigger every 10 minutes.
ScriptApp.newTrigger('myFunc') //Run Update All Sheets
.timeBased()
.everyMinutes(10)
.create();
}
and outside the script. I wonder which of these works on background.
// Trigger every 10 minutes.
ScriptApp.newTrigger('myFunc') //Run Update All Sheets
.timeBased()
.everyMinutes(10)
.create();
function onOpen() {
}
It is possible to add a trigger programmatically.
https://developers.google.com/apps-script/guides/triggers/installable
Managing triggers programmatically
You can also create and delete triggers programmatically with the Script service. Start by calling ScriptApp.newTrigger(functionName), which returns a TriggerBuilder.
The following example shows how to create two time-driven triggers—one that fires every 6 hours, and one that fires every Monday at 9 a.m. (in the time zone that your script is set to).
triggers/triggers.gsView on GitHub
/**
* Creates two time-driven triggers.
*/
function createTimeDrivenTriggers() {
// Trigger every 6 hours.
ScriptApp.newTrigger('myFunction')
.timeBased()
.everyHours(6)
.create();
// Trigger every Monday at 09:00.
ScriptApp.newTrigger('myFunction')
.timeBased()
.onWeekDay(ScriptApp.WeekDay.MONDAY)
.atHour(9)
.create();
}
This next example shows how to create an installable open trigger for a spreadsheet. Note that, unlike for a simple onOpen() trigger, the script for the installable trigger does not need to be bound to the spreadsheet. To create this trigger from a standalone script, simply replace SpreadsheetApp.getActive() with a call to SpreadsheetApp.openById(id).
triggers/triggers.gsView on GitHub
/**
* Creates a trigger for when a spreadsheet opens.
*/
function createSpreadsheetOpenTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('myFunction')
.forSpreadsheet(ss)
.onOpen()
.create();
}
To programmatically modify an existing installable trigger, you must delete it and create a new one. If you have previously stored the ID of a trigger, you can delete it by passing the ID as an argument to the function below.
triggers/triggers.gsView on GitHub
/**
* Deletes a trigger.
* #param {string} triggerId The Trigger ID.
*/
function deleteTrigger(triggerId) {
// Loop over all triggers.
var allTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < allTriggers.length; i++) {
// If the current trigger is the correct one, delete it.
if (allTriggers[i].getUniqueId() === triggerId) {
ScriptApp.deleteTrigger(allTriggers[i]);
break;
}
}
}
Open your google sheet
Click Tools
Click Script Editor
Make a function. Example Birth day greeting every day is shown below
function hbd_mail() { //birth day mail daily 7 am from hrd login
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Emp");
var today=new Date();
lastRow = sheet.getLastRow();
var values = sheet.getRange('A:T').getValues();
for (i=1;i<lastRow;i++){
if (values[i][14]=="") {} else {
if ( Utilities.formatDate( values[i][14] ,"GMT+05:30", "dd-MMM") == Utilities.formatDate( today ,"GMT+05:30", "dd-MMM") && values[i][18]=="Yes" ) {
var message = 'Dear '+ values[i][1]+',\n\nMegawin Collective wishes you a very happy birth day ('+ Utilities.formatDate( values[i][14] ,"GMT+05:30", "dd-MMM")+ ').\n\nHRD Megawin Switchgear Pvt Ltd';
var subject = "Happy Birth Day "+values[i][1];
if (values[i][7]=="") {} else {GmailApp.sendEmail(values[i][7], subject, message);}
}//if
}
}//for
}
Save the script
Click the Clock in the menu
It will ask you the function name - select the above function
Then select time based
Clcik every hour / day / week etc
Save it.
Now the function will run automatically from google server (at the frequency selected by you) without your having to do anything.
It is pretty simple.

Create a trigger that works if the person is not an editor

I want people to jump to the current date row when opening the sheet. However, this should be the case for everyone viewing the sheet and irrespective of their edit-rights. For example, I want that people edit the current date row in the sheet every day over the link. In this case, onOpen() does not work. Is there any alternative or modification to the function?
I am informed about onOpen trigger, however, this would not work if somebody is editing the sheet only over the link with edit rights.
This is e.g. the code I would like to work for everyone:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("B:B");
var values = range.getValues();
var day = 24*3600*1000;
var today = parseInt((new Date().setHours(0,0,0,0))/day);
var ssdate;
for (var i=0; i<values.length; i++) {
try {
ssdate = values[i][0].getTime()/day;
}
catch(e) {
}
if (ssdate && Math.floor(ssdate) == today) {
sheet.setActiveRange(range.offset(i,0,1,1));
break;
}
}
}
I found the options: Edit Triggers
To manually create an installable trigger through a dialog in the script editor, follow these steps:
From the script editor, choose Edit > Current project's triggers.
Click the link that says: No triggers set up. Click here to add one now.
Under Run, select the name of function you want to trigger.
Under Events, select either Time-driven or the Google App that the script is bound to (for example, From spreadsheet).
Select and configure the type of trigger you want to create (for example, an Hour timer that runs Every hour or an On open trigger).
Optionally, click Notifications to configure how and when you are contacted by email if your triggered function fails.
Click Save.
Google Explanation to Edit Triggers

How to click an empty google sheet cell and get the real time, NOW()?

I work for a transportation company and What I am trying to achieve is that every time a driver login or mobiles over the two-way radio, I want to click the empty cell and get the real time. I know there is a Now() function, in google sheets but if I use that all cells will have the same value, I want to get the current time when I click the empty cell.
I used the script editor to create buttons for a workaround that will show me in and out times, but I want to keep the original format of the sheet, here is the code below:
function setValue(cellName, value){
SpreadsheetApp.getActiveSpreadsheet().getRange(cellName).setValue(value);
}
function getValue(cellName){
return SpreadsheetApp.getActiveSpreadsheet().getRange(cellName).getValue();
}
function getNextRow(){
return SpreadsheetApp.getActiveSpreadsheet().getLastRow() + 1;
}
function setGeorge(){
setValue('M1','George,CSH2501')
}
function setTerry(){
setValue('M1','Terry,CSH2502')
}
function setDavid(){
setValue('M1','David,PSH3502')
}
function setSandra(){
setValue('M1','Sandra,PSH3508')
}
function setElioCalle(){
setValue('M1','ElioCalle,PSH3504')
}
function setWarren(){
setValue('M1','Warren,PSH3501')
}
function setShu(){
setValue('M1','Shu,PSH3503')
}
function setPaul(){
setValue('M1','Paul Prkash,PSH3507')
}
function setMei(){
setValue('M1','Mei Tsang,PSH3506')
}
function setJames(){
setValue('M1','James Clark,PSH3505')
}
function setElvira(){
setValue('M1','Elvira,PSH3509')
}
function addRecord(b, c, d){
var row = getNextRow();
setValue('A'+ row, b);
setValue('B'+ row, c);
setValue('C'+ row, d);
}
function punchIn(){
addRecord(getValue('M1'), new Date(), 'IN');
}
function punchOut(){
addRecord(getValue('M1'), new Date(), 'Out');
}
And the results are this:
=Now() is a volatile function, every time you change some data in the spreadsheet or refresh the sheet excel recalculates it. The only way to overcome is through a script, I created buttons using the drawing tool and assigned functions punchIn and punchOut for every time a driver mobiles and clears:
function punchIn(){
var sheet = SpreadsheetApp.getActiveSheet();
var now = new Date();
sheet.getRange('E3').setValue(now);
}
function punchOut(){
var sheet = SpreadsheetApp.getActiveSheet();
var now = new Date();
sheet.getRange('H3').setValue(now);
}
The only thing was I have to do this for every cell and every button as you can see from the image below. If there is a way to simplify the code any suggestion would be appreciated.
Nowadays it's possible to insert a timestamp when clicking a cell by using the onSelectionChange simple trigger.
The following example will add a timestamp to any cell / range selected
function onSelectionChange(e) {
e.range.setValue(new Date());
}
You can control on which cells the timestamp be added, i.e., by using if-statements and the event object.
After adding onSelectionChange trigger you have to reload the spreadsheet to make it start working.
When opening a spreadsheet from Google Drive or Google Sheets apps, the default active cell is the first cell of the first sheet, onSelectionChange will not run in this case but if you use a range link , i.e. https://docs.google.com/spreadsheets/d/spreadheetId/edit#gid=0&range=I5:I9, onSelectionChange will run.

Locking cells in Google Sheets at a specific time

I want to code my Google Sheets cells in a way that certain cells automatically lock at a specific time every day. I should be able to edit it, but not my collaborators.
How do I pull this off?
In the sample sheet (link here), you will see certain dates (15/7/2015-17/7/2015). I want to code it so that each date (eg A1:B6) is locked daily, 10 pm.
As #NightShadeQueen suggested a combination of Time-driven triggers and the protect()-method of the Class Range can be used.
Open the script editor in the sheet (Tools > Script editor...)
Create code that locks the ranges, might look something like this:
You'll have to modify the code if your sheet doesn't look like the Sample sheet. Especially the lockRanges()-function, which defines which ranges should be protected. Currently, it starts with cell A1, and steps down 7 rows at a time until the end of the sheet is reached.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1'); //INSERT SHEET NAME HERE
function lockRanges() {
//First cell to lock
var row = 1;
var col = 1;
// Get last row with data in sheet
var lastRow = sheet.getLastRow();
//Loop until last row in sheet is passed
while(row <= lastRow){
//Lock current cell
lockRange(row, col);
// Go to row 7 steps down from current (the next date)
row = row + 7;
}
}
function lockRange(row, col){
var range = sheet.getRange(row, col);
// Create protection object. Set description, anything you like.
var protection = range.protect().setDescription('Protected, row ' + row);
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
Add the Time-driven trigger
Still in the Script editor; go to Resources > Current project's triggers.
Create a new trigger
Choose Run = lockRanges
Choose Events = Time-driven, Day timer, 10pm to 11pm (or whenever you want)
NOTE: The time may be slightly randomized (read more)
That's it, now the ranges will be protected at the time you chose. As with ranges you protect manually, they show up in Data > Protected sheets and ranges.
Something unclear? Ask away!