Automatically Restore Previous Version of a Google Document - google-apps-script

I work in a school, and have teachers fill out a point chart every week in google sheets. At the end of the week, I save the information and restore the sheet to it's blank state as it was at the beginning of the week.
I'm looking for an add-on that will automatically restore a previous version of my sheet on a weekly basis at a certain time. Have you ever come across an add-on that does something similar?

For this you can write an Apps script function with the content below:
// This example assumes there is a sheet named "first"
var ss = SpreadsheetApp.getActiveSpreadsheet();
var first = ss.getSheetByName("first");
first.clearContents();
And add a time driven trigger to that function to run once a week.
Hope that helps!

Related

How to protect the cell/range at the same time as appendrow

Im working on a website that stores data in a google spreadsheet and was wondering how I could use the appendrow() function and then protect that cell so no one can access it.
I'm new to google apps script and have been searching the internet for the last hour or so and can't find anything.
sheet.appendRow([text]);
But after that I would like it to get the value of that cell that was just written on so I could write:
var protection = the-row-just-written-on.protect()
I I am hoping for the result to be that no one can delete the text once it has been written on.

Google Sheets - Replace sheet without breaking references to that sheet

We are building a google sheets database where each user has their own spreadsheet that accesses a central sheet for information using apps script.
This means that with 50 employees, we have 50 spreadsheets to maintain. I am trying to find a way to push updates to all 50 spreadsheets without having to update each one manually. I have all the apps script code in a library that each user's sheet references, so I have the coding maintenance figured out. But keeping each users actual spreadsheet up to date with the latest features is proving difficult.
One way I'm figuring to do that is have a "Template" user sheet that gets updated with the changes/new features. Then when each user opens their spreadsheet, it cross references all of its sheets to the template sheet, and checks if it needs to replace it's sheet with the latest sheet based on time that it was updated in the template sheet. For example, when the sheet "Project Report" in the template is newer than the "Project Report" sheet in the user's spreadsheet, the user SS deletes it's current "Project Report" and copies the template "Project Report" sheet to it's own via the copyTo() method.
I have this all working with apps script, but the issue now is that when the user's local sheet is deleted and replaced with the new updated seet, all formula references to that sheet in other sheets break and replace the reference with #REF. I had planned on overcoming this by using only Named Ranges, but even the named ranges break when the sheet is replaced to the point where even the apps script can no longer find the named range because the named range it is looking for was automatically renamed when the new version of the sheet was imported (aka, "CustomNamedRange" in the template SS was renamed to "'SheetName'!CustomNamedRange" in the user SS).
The only way I know to overcome this issue at this point is to create a centralized "Range Index" spreadsheet that has all the named ranges with their destination sheet and range. I would have to create a custom function that filters through the range index and finds the address it needs based on the name given. For example, instead of calling "CustomNamedRange" in a sheet formula, I would call custom function: getNamedRange("CustomNamedRange"), and apps script would return the range found in the range index. And when a sheet is replaced with the newer version, no references would break because all references go through the apps script filter function.
The only problem with this is that I can foresee this method (calling every range needed in the script through a custom function) slowing down my spreadsheet A LOT because every time a range is called for, it will have to go search through the range index to find it and return it.
Does anyone have any other ideas on how to accomplish what I'm looking for? As in keeping 50+ individual spreadsheets updated with new features without having to do it manually and without breaking all the references?
Sorry for the long post, but I appreciate any ideas!
I had a similar problem and was able to resolve it by using SheetAPI to replace text. I have a template called Sheet1_Template and its hidden. I delete Sheet1, copy Sheet1_Template, show it and then replace all occurances of "Sheet1" in formulas to "Sheet1". Sheet API has to be enabled in the Resources and Google API Console.
function copyTemplate() {
try {
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spread.getSheetByName("Sheet1");
if( sheet !== null ) spread.deleteSheet(sheet);
sheet = spread.getSheetByName("Sheet1_Template");
sheet = sheet.copyTo(spread);
sheet.setName("Sheet1");
sheet.showSheet();
sheet.activate();
spread.moveActiveSheet(0);
var requests = {"requests":[{"findReplace":{"allSheets":true,"find":"Sheet1","replacement":"Sheet1","includeFormulas":true}}]};
Sheets.Spreadsheets.batchUpdate(requests, spread.getId());
}
catch(err) {
Logger.log("error in copyTemplate: "+err);
}
}
I haven't been able to test implementation of it yet, but I believe the answer above is what I was originally looking for.
I haven't spent any time messing with the API yet, so in the meantime I have found another solution:
Google Sheets recently added macros to it's feature set. The beauty of this is that You can see and edit the macro code after you've recorded your actions in the sheet. For now, I plan on recording a macro when I make updates to the template sheet, then copying the script for that macro into a custom function in my library that will run every time a user opens their spreadsheet. When they open their SS, apps script will check to see if the library's macro function has a later date than the last time the sheet was opened. If it does have a new date, then it will run the macro script, and that user's SS should get updated to the same state as the template.
Also if you are seeing that you cannot run the query from #TheWizEd
It may be due to "Sheets API" not being enabled at Advanced Google services. Please enable>
In the script editor, select Resources > Advanced Google services In the dialog that appears, click the on/off switch for Google Sheets API v4. Please turn on. Click OK button.
Thank you so much to TheWizEd for getting me started (please vote for that post too).
This is what I needed:
function replaceFormulasInSheet(sheet, searchFor, replaceWith) {
// https://stackoverflow.com/a/67151030/470749
// First you need to do this to enable the feature: https://developers.google.com/apps-script/guides/services/advanced#enabling_advanced_services
// https://developers.google.com/sheets/api/quickstart/apps-script
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#findreplacerequest
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/batchUpdate
const spread = SpreadsheetApp.getActiveSpreadsheet();
const requests = {
"requests": [
{
"findReplace": {
// "allSheets": true, Omitting this property and instead setting the sheetId property is the only way to effectively set allSheets as false.
"sheetId": sheet.getSheetId(),
"find": searchFor,
"replacement": replaceWith,
"includeFormulas": true
}
}
]
};
return Sheets.Spreadsheets.batchUpdate(requests, spread.getId());
}
Also note that it does not work for sheets with hyphens in their names. If you need hyphens in their names, remove the hyphens beforehand and re-add them after.

IMPORTRANGE function not refreshing new entries in linked Google sheet

My IMPORTRANGE function is not refreshing with new data once the linked spreadsheet is added to. Instead, I am having to cut and paste all of the formulae again whenever I want to view the new information.
I'm using the new version of Google Sheets and I know there were some issues around the release of this with the IMPORTRANGE function.
I currently have 24 columns of data that I'm importing and the original spreadsheet will just keep growing as it is linked to a form. This is the main reason I'm using IMPORTRANGE, as it will help to keep the original spreadsheet working at maximum speed.
What I'd like to know is, has anyone else had a problem such as this, and if so is there any work around (in apps script/another function)? In worst case scenario, is there an apps script about which would clear the spreadsheet and re-enter all of the formulae on open/on a menu click as it really is a pain updating every column every time a new entry is made.
EDIT - Almost all of the cells I'm trying to import are formulated within the original spreadsheet if that changes anything - EDIT
In the spreadsheet settings under "File", go into the Calculations tab and change the Calculation Setting to "On Change and every minute". I had to do this on another importrange sheet and it did the trick for me.
What solves the problem? Setting the same owner for both spreadsheets: the one that you import data from and the one where you use importrange formula. I had the same problem. I updated the source and no response on final spreadsheet. After setting same owner for both spreadsheets refreshing takes few seconds
I've worked out an ultimate (and very simple) solution to any importrange problems. Let's say you have your data in Sheet1 and it's being collected from a google form. You'd like to importange it somewhere else but newly received rows don't trigger importrange refresh. The solution is to move the data using QUERY to Sheet2 (in the same file) and then importrange the data from Sheet2 to another file; it's easy to force refresh of the QUERY function using simple macro, below I pasted simplified version of my function:
function myFunction() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Sheet2'), true);
spreadsheet.getRange('A1').activate();
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getCurrentCell().setFormula('=QUERY(\'Sheet2\'!A:Z;"SELECT *";1)');
};
So basically I clear the A1 cell that contains the QUERY formula and then I fill it with the same QUERY formula. I set this macro to trigger every 1 minute. Works like a charm.
A trick that seems to work
Instead of
=importrange("Relevant_Sheet_ID","Archive!a1:p259")
Use the below just adding => &"?"&now()
=importrange("Relevant_Sheet_ID"&"?"&now(),"Archive!a1:p259")
Basically, it fools GoogleSheets to think the data set referred is ever changing by adding a timestamp through a now() function.
Feedback welcomed, seems to work for me, but might not be consistent.
Click File > Spreadsheet Setting... and check both sheets are in the same Locale and if responces are comming from Jotforms, set the same Locale there too.
Make a copy of your master sheet and change url of your importrange function. it's work for me..
=importrange(new_master_sheet_copy_url,string_range)

How do I create an Auto-Clear Script in a Google Spreadsheet?

I could use some help with writing a script in my Google spreadsheet. First off, I am no programmer and a novice at best on writing code or any script.
I want to use this for a lunch list. The back story: I created Google spreadsheets to act as a digital lunch sheet. Each teacher has their own spreadsheet for their homeroom and the totals for the class populate a master lunch sheet for the head cafeteria worker for ordering. The problem is that the old totals are still present from the day before. Ideally, on the start of a new day, the specified fields on the spreadsheet will auto clear. Click here to view an example of the spreadsheet I created.
In my research I found a thread on how to create a script to do this, but as a button to click that will then clear specified ranges Click here to see the original post. The script is as followed:
function clearRange() {
//replace 'Sheet1' with your actual sheet name
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
sheet.getRange('C4:I12').clearContent();}
What I would like for is there to be a script so that everyday (say everyday at midnight) a specific field/ range is cleared out. I do not want columns or rows to delete because I do not want to lose student names or lunch selections.
Please, any help is greatly appreciated. Thanks in advance for your help, especially with a novice like me. I look forward to hearing from anyone!
- Jason
Follow these steps...
01. Go to https://script.google.com and then add a New Script.
ᴬᵈᵈ ⁿᵉʷ ˢᶜʳⁱᵖᵗ
02. Paste this function
function clearRange() {
// replace 'Sheet1' with your actual sheet name
// replace 'dhrhrejYOURSHETIDerhe5j54j5j' with your actual sheet ID
var sheetActive = SpreadsheetApp.openById("dhrhrejYOURSHETIDerhe5j54j5j").getSheetByName("Sheet1");
sheetActive.getRange('A:Y').clearContent();
}
ˢᵖʳᵉᵃᵈˢʰᵉᵉᵗ ᴵᴰ ᴱˣᵃᵐᵖˡᵉ
03. Goto Run & select Run function and then select clearRange.
Once you have run the script, your spreadsheet should be cleared.
 
Follow these steps if it works correctly...
04. Goto Edit, Select 'All your triggers'
05. In 'All your triggers' popup windows, select clearRange as the Run function.
06. Set the time as you like. (See the example image)
That script should do what you need. You just need to make a couple of modifications.
Where is says 'Sheet1' you would use 'Lunch' which is the name of your sheet in your example.
In the Script Editor, you can add a new trigger to have the script run every night.
In the Script Editor, go to the top menu "Resources » Current Project's Triggers"
Click the link "No triggers set up. Click here to add one now."
Make sure you set these values:
Run » clearRange
Events » Time-driven
Day Timer
Midnight to 1 am
That should run your script every night sometime between Midnight to 1 AM.
If you want an actual menu item that you can click on within the spreadsheet so you can run the script anytime you want, that's a bit more work. Honestly, if that's your primary function ... it's probably just easier to load up the Script Editor from the spreadsheet ("Tools » Script Editor"), and just select the clearRange function and press the play button.
If you do really want to add menu items, there's additional documentation here » https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#addMenu(String,Object). Once you've coded the new menu function, you'll have to update your triggers just like you did to run every night. But instead, you'll change the event type to From Spreadsheet and set the value to On open. That way it'll create the new menu items when the Spreadsheet is opened.

script to force republish of google spreadsheet

I have created a form that pushes data to a Google Spreadsheet. The data is latitude, longitude, location, and other identifying data. The spreadsheet is then published as a .CSV file and imported into ARC GIS to be displayed on an interactive map. It works exactly as I wanted and I set it to republish after each change.
The problem is that when the spreadsheet has rows appended by the script, it is not seeing it as a change and republishing. In order to get the updated data imported to the map, I need to go in and manually republish. Is there anyway through the Google Apps Script that I could make a few lines of code to force a republish? I could then add that to the "on form submit" script I have or another time based one that already runs at 3 am everyday.
I have looked through the Google Apps Script documents and not found anything. When searching for help on the web, the overwhelming majority of responses are for how to publish your script as a template for other.
My testing sheet was republished after the following function was executed by either a menu entry or a time-based trigger.
function ChangeIt() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var t = new Date()
var x = 'upd: ' + t
var range = sheet.getRange('a3')
range.setValue(x)
}
If I were in your shoes, I'd add an extra column to the end of the sheet with some benign constant data that a script can change without affecting the systems consuming the data. If an extra column isn't an option, try modifying my sample to read in a current value, change it, and immediately change it back.
Also, I'd see if the spreadsheet onEdit() trigger fires when the form submit adds a new row. If so, tie your GAS function to it to force the republish. If not, setup a timed trigger to execute the GAS function.
A quick workaround for this issue that doesn't require scripting is to simply make an array copy of the data.
For example, I made a new tab and in A1 put this: =ArrayFormula('Form Responses 1'!A1:Z1000)
While the main Form responses tab will insert rows and not play nice with formulas this new tab stay nice and constant and updates automatically when new data is added.