Copy and Paste values (as Text) every hour from a Static Table - google-apps-script

I'm new to scripts as you can see, I need a script where in I can get a data on a table (Sheet 1!A1:E7 - which updates every hour as well) and copy it (as TEXT) to a new sheet (Sheet 2). I need Sheet 2 to generate new rows/columns with the every hour (24 hrs) for 7 days. I searched the whole net to find this, but to no avail though.
Hoping to find answers to this.

Surpised the internet didn't throw up anything to learn how to script, but will share the route I took with you.
Codeacademy. Great for learning the basic priciples of Javascript
Once you've done there, next stop should be here.
This is googles reference site for scripting. But also has a few have a go tutorials that give insight into Google Application scripts and how they work.
That should give you a great starting point to build your own scripts.
I'd also keep this link to hand, for great rerefences, W3Schools
Has javascript references and tutorials
You'll be on your way in no time at all, and once you hit brick walls, or code isn't behaving properly. There is good old HERE, StackOverflow to visit.
I don't understand what you mean in your question "Generate new columns"
because if the source table is always A1:E7 then you don't need extra columns on sheet 2. Only extra rows as new data is imported.
This is a quick solution to your question.
function tableCopy() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("Sheet1");
var targetSheet = ss.getSheetByName("Sheet2");
var values = sourceSheet.getRange("A1:E7").getValues();
var valuesLength = values.length;
if (!valuesLength) return;
var lastRow = targetSheet.getLastRow();
var requiredRows = lastRow + valuesLength - targetSheet.getMaxRows();
if (requiredRows > 0) targetSheet.insertRowsAfter(lastRow, requiredRows);
targetSheet.getRange(lastRow + 1, 1, valuesLength, values[0].length).setValues(values);
}
to get it working as a timer, you will have to add a time driven trigger to the function. To trigger it at the times you require.
I hope this helps

Related

Struggling to Create a Simple Copy/Paste Script

I've been trying to learn on my own by watching YouTube videos and reading forums, but I'm still struggling and...I'm a little embarrassed because it seems so simple. I'm hoping any answers/suggestion from you will help me in the future.
I have two sheets "Bishop" and "Log". I want to copy two specific cells (K11 and K12) from "Bishop", which are vertically aligned, and paste them horizontally in the sheet "Log" at C4 and D4, respectively, without any formatting or formulas being copied over.
Each time I press a button (I've already made and attached a script to) I want it to paste in those two cells, and then move down to the next empty row (so C4,D4 to C5,D5, C6,D6...and so on).
I never intended on getting someone to finish my script for me, but I'm getting confused by the examples I've found in my research. Here's my script so far (after deleting many dysfunctional versions)
function Logger(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var bishop = ss.getSheetByName('Bishop');
var log = ss.getSheetByName('Log');
}
I tried to copy and modify code examples from YouTube videos and articles, but I think my by modifying them I'm just making a mess.
Thank you for any help or suggestions.
Dustin
EDIT
After some tinkering and reading some more, I now have a pretty nifty script that copies data in to where I want it! However, my next goal is to learn how to move down one row each time I run the script, so it creates an actual list, or log. "InputData" and "PasteRange" are named ranges on my source sheet and destination sheet, respectively. Here's my code so far:
function Logger(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var bishop = ss.getSheetByName('Bishop');
var log = ss.getSheetByName('Log');
ss.getRange("InputData").copyTo(log.getRange("PasteRange"),SpreadsheetApp.CopyPasteType.PASTE_VALUES,true);
}
So far your script has gotten to the point of creating 2 variables that reference the Bishop and Log sheets.
Next, you'll need to select the specific ranges in those sheets. To get a range in a sheet, use the getRange method, which has a few variations on what inputs it takes. For example:
var range1 = sheet.getRange("A1");
Once you have references to the ranges, you can use the getValue or getValues method to extract the values inside a range, and then use the setValue or setValues method to overwrite new data into an existing range. For example:
var myValues = range1.getValues();
range2.setValues(myValues);
If you haven't seen this page before, take a look; it's probably the most helpful single webpage for writing sheet scripts.
(Also, I won't write the code for you; Stackoverflow is about specific questions and answers, not about figuratively doing your homework, though the lines are blurry at times. But feel free to keep asking questions!)

Google sheets script - copy varying data from one sheet to another in same spreadsheet

I wonder if you could please help me solve this. My knowledge of scripts is quite poor, despite attempts to learn.
This is an example of my spreadsheet.
Each month, in the Monthly sheet, I copy data from all the rows below the frozen ones (columns B, C and D only) and make a note in my head of the number of rows copied (the figure shown in cell E2, which can vary). I then go to the Daily sheet, insert the required number of rows at the top of the unfrozen section, and paste in the data values (CTRL Shift V).
I've been trying unsuccessfully to automate this with a script. I've tried piecing bits of code together from other solutions, but the different methods used and my lack of knowledge mean I can't get them to work.
Hoping you can help.
Many thanks.
You can do the following:
Retrieve the desired range from Monthly, using Sheet.getRange.
Taking into account the source range number of rows via Range.getNumRows(), insert the corresponding number of blank rows to Daily (starting at row 4, first unfrozen one) using Sheet.insertRowsBefore.
Copy the retrieved range to Daily!B4 (first unfrozen row) using Range.copyTo.
Code snippet:
function copyRange() {
const ss = SpreadsheetApp.getActive();
const monthlySheet = ss.getSheetByName("Monthly");
const dailySheet = ss.getSheetByName("Daily");
const firstRow = 5;
const sourceRange = monthlySheet.getRange(firstRow,2,monthlySheet.getLastRow()-firstRow+1,3);
dailySheet.insertRowsBefore(4, sourceRange.getNumRows());
const destRange = dailySheet.getRange("B4");
sourceRange.copyTo(destRange,SpreadsheetApp.CopyPasteType.PASTE_VALUES,false);
}
Having tried and failed to do this quite a few times, I've now managed to produce something that seems to work by recording a macro, working out what each line or section in the resulting script does, and editing it, with some additional online research required. It might be a bit clunky, but here's the result of my efforts:
function CommitMonthly() {
// Script is only ever run from the Monthly sheet via the Commit button. Get the number of rows.
var spreadsheet = SpreadsheetApp.getActive();
var NumberOfRows = spreadsheet.getRange('E2').getValue();
// Select the Daily sheet, select top row, insert required number of rows above it.
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Daily'), true);
spreadsheet.getRange('B4').activate();
spreadsheet.getActiveSheet().insertRowsBefore(spreadsheet.getActiveRange().getRow(), NumberOfRows);
// Copy and paste the data from Monthly to new rows in Daily.
spreadsheet.getRange('Monthly!B5:D').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
};
Many thanks for your help.

How to remove google apps script "Exception: Conditional format rule cannot reference a different sheet."

I have several similar spreadsheets I am working with. Each spreadsheet has 3 sheets of the same name: "Plan", "Class", and "Coach". I want the conditional formatting within the sheets of my spreadsheets to be exactly the same. I was helped a little while ago in creating a script that could do so, and it worked perfectly fine in my test spreadsheets (I don't like to put something in my actual spreadsheets until I know it will work properly). The script uses getConditionalFormatRules on all the sheets from my source sheet and then uses setConditionalFormatRules and the other sheet ID's to recreate the source spreadsheet's rules in my other spreadsheets. I have now placed my code into the actual spreadsheet, but I am now experiencing a problem.
Every time I run my script, I get this error:
Exception: Conditional format rule cannot reference a different sheet.
I get this message when the script is copying the conditional formatting from the sheet called "class". The other two sheets' formatting gets copied perfectly fine. I have gone over the code many times now, but I can find no error in my code. I have tried creating new sheets and starting over, and then referencing the recreated sheets, but I still get the same message. I have tried changing the sheet name as well, but to no avail (plus, I would rather not change the sheet name from "Class" because many of my other scripts would also have to change). I am very lost.
This is my current script:
function copyConditional(){
var targetT = SpreadsheetApp.openById("Tuesday_ID").getSheetByName("Plan");
var targetW = SpreadsheetApp.openById("Wednesday_ID").getSheetByName("Plan");
var targetTh = SpreadsheetApp.openById("Thursday_ID").getSheetByName("Plan");
var targetF = SpreadsheetApp.openById("Friday_ID").getSheetByName("Plan");
var targetS = SpreadsheetApp.openById("Saturday_ID").getSheetByName("Plan");
var source = SpreadsheetApp.openById("Monday_ID").getSheetByName("Plan");
var rules = source.getConditionalFormatRules();
targetT.setConditionalFormatRules(rules);
targetW.setConditionalFormatRules(rules);
targetTh.setConditionalFormatRules(rules);
targetF.setConditionalFormatRules(rules);
targetS.setConditionalFormatRules(rules);
var targetT2 = SpreadsheetApp.openById("").getSheetByName("Coach");
var targetW2 = SpreadsheetApp.openById("").getSheetByName("Coach");
var targetTh2 = SpreadsheetApp.openById("").getSheetByName("Coach");
var targetF2 = SpreadsheetApp.openById("").getSheetByName("Coach");
var targetS2 = SpreadsheetApp.openById("").getSheetByName("Coach");
var source2 = SpreadsheetApp.openById("").getSheetByName("Coach");
var rules2 = source2.getConditionalFormatRules();
targetT2.setConditionalFormatRules(rules2);
targetW2.setConditionalFormatRules(rules2);
targetTh2.setConditionalFormatRules(rules2);
targetF2.setConditionalFormatRules(rules2);
targetS2.setConditionalFormatRules(rules2);
var targetT1 = SpreadsheetApp.openById("").getSheetByName("Class");
var targetW1 = SpreadsheetApp.openById("").getSheetByName("Class");
var targetTh1 = SpreadsheetApp.openById("").getSheetByName("Class");
var targetF1 = SpreadsheetApp.openById("").getSheetByName("Class");
var targetS1 = SpreadsheetApp.openById("").getSheetByName("Class");
var source1 = SpreadsheetApp.openById("").getSheetByName("Class");
var rules1 = source.getConditionalFormatRules();
targetT1.setConditionalFormatRules(rules1);
targetW1.setConditionalFormatRules(rules1);
targetTh1.setConditionalFormatRules(rules1);
targetF1.setConditionalFormatRules(rules1);
targetS1.setConditionalFormatRules(rules1);
}
The only thing I changed in this code was taking out my sheet ID's, but I can guarantee I had all the correct ID's in the right spots.
I would like to know what I can do to remove the exemption from my script, or if there is maybe another workaround to allow the script to function properly. Thank you!
Edit
This is an image of part of my sheet. The first two rows have rules that will change the background color and font color of a cell depending on its exact value. There is also one rule for every 6 columns (except for the first) that will change the cell's background color if any information at all is entered.
Edit 2
These are all the rules on sheet "Class" as of the moment. I do add rules pretty frequently, but following the same pattern. I am using my script because it can be very time consuming to have to add the same new rule to all 6 of my sheets individually.
My other sheet "Coach" has all the same "text is exactly" rules, except the range changes from A1:EO2 to A1:BF59. The other sheet "Plan", has all the same "text is exactly" rules, but changes the range to A1:AU59. Sheet "Plan" also has some unique rules, which I will add as well.
EDIT
I never found out why the script did not work on my original sheets. I had to recreate all of my sheets from scratch, rewrite my script in the new spreadsheets, and paste in the new spreadsheet ID's into my script to get my desired effect. At this point, I have determined there must have been some fundamental flaw in the sheet itself, and that my problem had nothing to do with my code.
I am not posting this as an answer, because creating new spreadsheets from scratch did not exactly solve the problem. I consider it a lengthy and annoying workaround more than a functioning solution. Thanks to everyone who tried to help though!

Is there a way to determine when a spreadsheet is done calculating?

I've a spreadsheet with a lot of imports and formulas based on the imports. Sometimes it takes a long time to update -- there is now a progress bar in the upper right that pops ups the message "calculating formulas" when you hover over it. It there a programmatic way to detect when the sheet is done recalculating?
I'd like to popup a box (toast?) saying the sheet is busy and then disappear the box when the sheet is done recalculating.
Not really.
Volatile functions like Importrange are the enemies of spreadsheet stability. Sometimes they get stuck recalculating and never finish; that is for nor particular reason as creating a copy usually creates a version that finishes calculating (eventually).
If you work with many importrange formulas and formulas based on them it is generally advisable to replace the import formula by a scheduled import via script.
This seems to work so far:
SourceWB = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/185XVLyN4fFLds8Z7JIgkL6mGl1CC82maBmmVAhYP71g/");
SourceRange = SourceWB.getRangeByName("CoreElementExport");
SouceValues = SourceRange.getValues();
var sourceRows = SourceRange.getNumRows();
var sourceColumns = SourceRange.getNumColumns();
DestWB = SpreadsheetApp.getActive();
DestSheet = DestWB.getSheetByName("TaxonomyImport");
DestSheet.getDataRange().offset(0, 0, sourceRows, sourceColumns).setValues(SouceValues);
something after, just trying to use this very complicated input tech...

Google Script for deleting blank or unused columns

I have searched and searched but can't find anything that works. I am trying to eliminate any empty columns that remain in the spreadsheet when creating a Google Form. It would be helpful because I have a formula for the sum of a string comparison in the sheet, but I don't want it to include comparisons of empty cells. (i.e. I compare the entries in from H:X in every individual row to H2:X2 and have it count how many are the same.) I know I could adjust the formula, but I am looking to build a template for fellow colleagues so they don't have to worry about altering anything. If I could get the empty columns at the end to disappear automatically, I could just change the sum formula to extend all the way to column CZ (just to be sure it goes far enough), without it calculating blanks in its comparison.
Any help would be great! Thanks!
i use these scripts in the script editor of my google sheets for cleaning them up. stumbled across them somewhere... perhaps they will help.
//Remove All Empty Columns in the Entire Workbook
function removeEmptyColumns() {
var ss = SpreadsheetApp.getActive();
var allsheets = ss.getSheets();
for (var s in allsheets){
var sheet=allsheets[s]
var maxColumns = sheet.getMaxColumns();
var lastColumn = sheet.getLastColumn();
if (maxColumns-lastColumn != 0){
sheet.deleteColumns(lastColumn+1, maxColumns-lastColumn);
}
}
}
//Remove All Empty Rows in the Entire Workbook
function removeEmptyRows() {
var ss = SpreadsheetApp.getActive();
var allsheets = ss.getSheets();
for (var s in allsheets){
var sheet=allsheets[s]
var maxRows = sheet.getMaxRows();
var lastRow = sheet.getLastRow();
if (maxRows-lastRow != 0){
sheet.deleteRows(lastRow+1, maxRows-lastRow);
}
}
}
This is something you will have to get used to when using Google forms. Data is never really erased if you physically delete rows/columns, they will just reappear at some unknown time in the future. It's a pretty buggy and unreliable setup.
My advice is to keep your formulas and data completely separate. You do this by copying the form responses to another sheet (using code or otherwise). That sheet allows you to control the data being fed (or NOT fed) to the rest of your system. I would also go 1 step further and use formulas like
ImportRange(SheetSource!A:A)
in a 3rd sheet to allow you to control the order of the columns. From there you can add your formulas to act on the data being fed through in relative safety.
However, I had a situation not long ago, where the form and the sheet randomly lost their linkage, and it was not possible to restore it. I stayed up until 6am trying to fix the issue, however if I did not have the data copied to the separate sheet (as described above) the catastrophe would have been complete.
Luckily this appeared to have been a random glitch, because everything went back to normal at about 10am, but put simply, your data is not truly safe with Google Forms.
Using Arrayformula is better suited for this though it does the same thing.
Example:
=ARRAYFORMULA('Form Responses'!A1:EA)
Importrange has a noticeable (and annoying) delay as this what you would use if you wanted to reference sheets from other spreadsheet files. Arrayformula references sheets within the same file, no delays.