I have a Google file with 5 sheets. 4 of them are dedicated to be filled by specific people (1 person fills his own sheet but hasn't any access to others') and the 5-th one is for calculating the total from these 4.
So the goal is to set a specific time when these spreadsheets could be filled. Let's say every Friday from 9 am to 6 pm. How can I do this part?
I am really new to GAS
Use Time-Driven Triggers
There is a feature in Google Apps Script wherein you can set the exact time wherein a function can be triggered.
Script
You can use the following code as the basis for your script:
const users = ["user1#gmail.com", //user1
"user2#gmail.com", //user2
"user3#gmail.com", //user3
"user4#gmail.com"]; //user4
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh1 = ss.getSheetByName("Sheet1");
const sh2 = ss.getSheetByName("Sheet2");
const sh3 = ss.getSheetByName("Sheet3");
const sh4 = ss.getSheetByName("Sheet4");
function enableUsers() {
sh1.protect().removeEditors(users).addEditor(users[0]);
sh2.protect().removeEditors(users).addEditor(users[1]);
sh3.protect().removeEditors(users).addEditor(users[2]);
sh4.protect().removeEditors(users).addEditor(users[3]);
}
function disableUsers() {
sh1.protect().removeEditors(users);
sh2.protect().removeEditors(users);
sh3.protect().removeEditors(users);
sh4.protect().removeEditors(users);
}
Set the Time-Driven Triggers
To add time-driven triggers, go to the triggers tab.
For enabling the sheets, set enableUsers to be triggered every friday 9am to 10am.
For disabling the sheets, set disableUsers to be triggered every friday 6pm to 7pm.
References:
Class Protection
Related
needs help regarding the macro
I currently have such a code
function getDynamicRows(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('B.Wioski');
var sourceRange = sheet.getRange('A1:F26500');
var data = sourceRange.getValues(); // Array of arrays [[Row1],[Row1],[Row3]]
// add data to next empty row in the static sheet.
var targetSheet = ss.getSheetByName('TW');
data.forEach(function(row){
targetSheet.appendRow(row)
}) ;
}
but the google sheet has a problem because the macro works max 6 min and it reads a maximum of 400 lines
and I would need a Macro that would copy A1 cells to F26500 where it would perform this activity 4 times a day every 6h for a maximum of 7 days and then on the 8th day it would delete the first day or overwrite the cells again
Instead of appendRow() use setValues().
If you keep exceeding the 6 mins, you can create multiple triggers (Row 1-5000, 5001-1000...) or copy the entire sheet and set formulas in your 'TW' sheet making reference to the copied sheets.
I have a spreadsheet where users can enter data and then execute a function when clicking on a button. When the button is clicked it logs the time and entered data in a new row on another sheet in that spreadsheet.
To make sure that sheet is not accidentally edited by the users I want to create a non-shared backup of that data.
I import the range to another spreadsheet, but just importing the range means that if the original sheet is edited/erased that data will also be edited/erased, so I wrote the following script to log the changes as they come in.
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var incomingSheet = ss.getSheetByName('Incoming');
var lastRow = incomingSheet.getLastRow();
var incomingData = incomingSheet.getRange(lastRow,1,1,7);
var permanentSheet = ss.getSheetByName('PermanentLog')
var newdataRow = permanentSheet.getLastRow();
incomingData.copyTo(permanentSheet.getRange(newdataRow+1,1));
}
This works when Run from the Apps Script Editor, however, when I enter new data and click the button on the original spreadsheet, it logs the data to the log sheet there, and the range is imported to the 'Incoming' sheet of the new Spreadsheet, but the data is not copied over to the 'Permanent Log' sheet (unless I Run it manually from within the Apps Script Editor). It also works if I remove the ImportRange function from the first sheet and then just manually enter data in on the 'Incoming' sheet.
So does this mean new rows from an Imported Range do not trigger onEdit? What would be the solution? I don't want to run this on a timed trigger, I want to permanently capture each new row of data as it comes in.
Also, am I overlooking a more elegant and simple solution to this whole problem?
Thank you for your time.
This function will copy the data to a new Spreadsheet whenever you edit column 7 which I assume is the last column in your data. It only does it for the sheets that you specify in the names array. Note: you cannot run this from the script editor without getting an error unless you provide the event object which replaces the e. I used an installable onEdit trigger.
The function also appends a timestamp and a row number to the beginning of the archive data row
function onMyEdit(e) {
e.source.toast('entry');//just a toast showing that the function is working for debug purposes
const sh = e.range.getSheet();//active sheet name
const names = ['Sheet1', 'Sheet2'];//sheetname this function operates in
if (~names.indexOf(sh.getName()) && e.range.columnStart == 7) {
const ass = SpreadsheetApp.openById('ssid');//archive spreadsheet
const ash = ass.getSheetByName('PermanentLog');//archive sheet
let row = sh.getRange(e.range.rowStart, 1, 1, 7).getValues()[0];
let ts = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm:ss");//timestamp
row.unshift(ts, e.range.rowStart);//add timestamp and row number to beginning
Logger.log(row);//logs the row for debug purposes
ash.appendRow(row);//appends row to bottom of data with ts and row
}
Logger.log(JSON.stringify(e));
}
Restrictions
Script executions and API requests do not cause triggers to run. For example, calling Range.setValue() to edit a cell does not cause the spreadsheet's onEdit trigger to run.
https://developers.google.com/apps-script/guides/triggers
So yeah, as far as I understand you it can't be done that way.
What I'm trying to achieve is really simple however I'm super uncomfortable with the Google Sheet Script Editor.
I want the date in a certain cell updated whenever something changes on the active sheet.
That's what I got so far:
//Timestamp on change
function timestampOnChange() {
getActiveCell().setValue(new Date());
}
However, even that already returns error messages :/
Explanation:
You need to create an onChange() trigger of a particular
function which will update a specific cell of the active sheet when the spreadsheet
changes content or structure.
The updateCell() function updates the value of B1 with the current
timestamp of the active sheet.
I would advice you to update a specific sheet instead of the active
sheet by using:
const sh = ss.getSheetByName('Sheet1');
instead of:
const sh = ss.getActiveSheet();
Solution:
In more detail, The createOnChangeTrigger() function will create
the onChange() trigger that will execute updateCell() when there
is a change in the content or structure of the spreadsheet file and in our case the active sheet.
function createOnChangeTrigger(){
const ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("updateCell")
.forSpreadsheet(ss)
.onChange()
.create();
}
function updateCell(){
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
sh.getRange('B1').setValue(new Date());
}
Instructions:
Copy/Paste both functions in the script editor and execute createOnChangeTrigger() only once.
References:
onChange()
From the question:
//Timestamp on change
function timestampOnChange() {
getActiveCell().setValue(new Date());
}
However, even that already returns error messages
The above code returns an error because theres isn't a built-in Google Apps Script function named getActiveCell(). To get the active cell you could use
SpreadsheetApp.getCurrentCell()
or
SpreadsheetApp.getActiveRange()
or if you use an edit event object (let say that it's a assigned to e) you could use e.range
It's worthy to not that if you use setValue(new Date()) on the active cell what ever that was entered on that cell will be overwritten.
On Web Applications, a sister site of Stack Overflow, there a lot of Q/A about timestamps in Google Sheets, actually, there is tag for them ---> https://webapps.stackexchange.com/questions/tagged/google-sheets-timestamp. So far there are 102 questions with this tag.
For the scheduling of tennis matches, we have created a sheet in which 170 duo-participants can fill in their names. This sheet is accessible to everyone (so you do not even have to have a Google account)
However, we are looking for the appropriate script to protect the cells that are filled in against possible changes.
Currently a protect is set up when a cell is edited.
But unfortunately, the protect does not work if it is filled in by a non-logged-in person. The protection is made, but not applied.
Who can help us customize the script, so that once a day (eg midnight) all filled cells are protected by anyone (by trigger)
I have set up a copy that is accessible to those who can help.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var Sheet = ss.getSheetByName("PLANNING");
var Range = Sheet.getActiveRange();
var Row = Range.getRowIndex();
var Reeks = Sheet.getRange("D"+ Row);
if (Reeks.getValue() != "") {
if (Reeks.getValue() != "FOUT") {
Range.setNote('geboekt op: ' + new Date());
var LockRange = Sheet.getRange(Row, 6, 1, 2);
var protection = LockRange.protect().setDescription('Row ' + Row + ' Protected');
protection.removeEditors(protection.getEditors());
}
}
}
Instead of a simple trigger use an installable trigger.
Change the name of your function name onEdit to something else like protectOnEdit
Add the installable trigger to run protectOnEdit (or whatever you named your function)
The above because simple trigger function can't execute methods that require authorization like removeEditors
I'm trying to find the reason why the script does not work. Setting up a trigger does not seem to work anyway.
I think it has to do with the other protections that arise. The sheet was originally protected with the EXCEPTION of a specific range. If the script wants to secure a row in that specific range, both statements go against each other.
I will try to figure it out further in the coming days
I am experiencing some strange problems with protection in Google New Sheets. I have created a demo of what I am experiencing. The URL to the sheet is:
https://docs.google.com/spreadsheets/d/1IbAiqU6oN48Ql_wM3TeRl9TqG6DFsBKtc86jElv0Kbo/edit?usp=sharing
I have protected the sheet for edit by owner only except for rows 5 to 7 using the 'Sheet protect except certain cells' method under 'Data - Protected sheets and ranges...'
I also have a simple User Function menu which is invoked on open wich contains a simple Google Apps Script to insert a given number of rows (code below).
The following is happening when another user accesses the sheet:
The basic protection seems to be working. The user can only edit the rows 5 to 7.
The insert row function (selected under User Functions menu) produces a 'Service error: Spreadsheets'.
If the user tries to delete any of the 3 unprotected rows then the message 'Can't save your changes. Copy any recent changes, then revert to an earlier version...' appears in a red box at the top of the screen. Clicking on the 'revert to an earlier version...' link reverses the delete.
If I remove all protection then everything is 100% for the user - insert rows funtion - delete rows etc.
The functionality I have reproduced here is very similar to what I have been using in the old sheets for years without any problems (i.e. protecting certain areas of the spreadsheet from edit by shared users).
I must add, I posted the issue about the insert row function not working a couple of days ago.
Here's my function code:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{name: "Insert Rows", functionName: "insertRows"}];
ss.addMenu("User Functions", menuEntries);
}
function insertRows() {
var numRows = Browser.inputBox('Insert Rows', 'Enter the number of rows to insert', Browser.Buttons.OK);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var curs = sheet.getActiveCell();
var cursRow = curs.getRow();
var cursLastCol = sheet.getLastColumn();
sheet.insertRowsAfter(cursRow, numRows);
var source_range = sheet.getRange(cursRow,1,1,cursLastCol);
var target_range = sheet.getRange(cursRow+1,1,numRows);
source_range.copyTo(target_range);
Browser.msgBox('Insert Rows', +numRows+' rows successfully inserted.', Browser.Buttons.OK);
}
Can anyone help with this. I have some large customers I have built complex online spreadsheets for that now don't function correctly under New Sheets.
Try setting up a project trigger for onOpen() rather than using the simple onOpen(). Then it runs with your privileges rather than those of the current user. Just click on Resources/Current Project Triggers and add a new trigger.