Google Scripts copyto issue - google-apps-script

I am trying to get a row with a certain range to copy into the row after text ends. I had it working a few days ago, but cannot figure out where I am going wrong right now.
So far I have:
function getNextRow();
return SpreadsheetApp.getActiveSpreadsheet().getLastRow()+1;
}
function test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getRange('a4:e4')
var data = range.getValues();
var nextrow = getNextRow();
ss.getRange(nextrow).setValues(data);
}
I have attempted the copyto, but cannot seem to figure it out again from the google developer's page. Any help is appreciated, thank you!

For one thing, you never specify the sheet you are working with. Which sheet of the spreadsheet should this script act on? Use getActiveSheet to pick the active one, or getSheetByName to pick a particular sheet.
Also, your function getNextRow returns an integer, which is the number of the first row that's below all the data. So far so good. But then you call ss.getRange(nextrow) where nextrow is that integer... not good. This isn't one of the acceptable ways of using this method: it needs either A1 notation, or (row, column) pair of integers for a single cell, or (row, column, number of rows, number of columns) quadruple for a range of more than one cell. Which is what you have, so use
ss.getRange(nextrow, 1, data.length, data[0].length).setValues(data);
This says: starting in the row nextrow, column 1 (meaning A), select the range of same size as data. The pair data.length, data[0].length is how one gets the height and width of data array.
That said, there is an easier way to achieve what you want, using appendRow method. Here's a function that would replace all of your code:
function test() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange('a4:e4')
var data = range.getValues();
sheet.appendRow(data[0]);
}
This appends the content of A4:E4 in the active sheet to the bottom of the same sheet. The method appendRow takes a one-dimensional array, hence data[0] and not just data (which is two-dimensional).

Related

appendRow to specific location

I have the following function:
function addrow() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Sheet1");
ws.appendRow(["apple", "orange", "banana"]);
}
appendRow just adds the items in the array on the last available row on the spreadsheet.
how do i make it start from a designated row (say row #10) and then just keep adding rows, "pushing" all the other rows down?
so if i set the script to start on row 10, when i execute, items will go in row 10, when i execute again, items will go in row 10 again, and the items from previous execution will now be in row 11 etc..
appendRow always appends the data onto the last row, there is nothing we can do about it.
There are many possible ways to append in the middle of the sheet, but the easiest way is to use insertRows() or other insertRow functions:
insertRow functions:
Feel free to test them one by one and see if they are applicable to your issue. They are generally similar, but differs on how many and where they insert the row/s.
Code:
function addrow() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Sheet1");
var data = ["apple", "orange", "banana"];
// shift all rows down by one from row 10
ws.insertRows(10, 1);
// then insert data into blank row (10)
ws.getRange(10, 1, 1, data.length).setValues([data]);
}
Sample Data:
Sample Output:
Note:
If you are eager to use only the appendRow to append in the middle of the sheet, then there is a way but is not an optimal solution and just a hack. Here are the steps:
Copy and store all the data from 10th-last row into a variable
Delete the data on 10th-last row in the sheet
Use appendRow to append your data (The data now should be pasted on the 10th since 10th-last row are already deleted)
Use setValues to paste the original value of 10th-last into 11th-last based on the variable's length.

How do I write a script correctly for GSheets that copy and pastes different ranges without errors?

I have a script that works well to copy and paste a range from example Sheet1 range: A1:C200 to Sheet2 range: A1:C200. My problem is my rows constantly vary from 200 - 3000 rows depending on the data I have imported daily into my spreadsheet and at the moment I'm constantly having to manually write each range.
Is it possible to write a script that would adapt to a variable range of rows each time and copy an entire range from columns A,B,C to the last row of available data like the range formula: A1:C?
See script example.
Original Script: (works)
function copy() {
var OriginalRange=SpreadsheetApp.openById('Spreadsheet ID').getSheetByName('Sheet1').getRange("A1:C200");
var DestinationRange=SpreadsheetApp.openById('Spreadsheet ID').getSheetByName('Sheet2').getRange("A1:C200");
DestinationRange.setValues(OriginalRange.getValues());
}
Ideal variable range Script: (exception: does not match the number of rows errors)
function copy() {
var OriginalRange=SpreadsheetApp.openById('Spreadsheet ID').getSheetByName('Sheet1').getRange("A1:C");
var DestinationRange=SpreadsheetApp.openById('Spreadsheet ID').getSheetByName('Sheet2').getRange("A1:C");
DestinationRange.setValues(OriginalRange.getValues());
}
You just need getLastRow() to get the last row with content. You just need to restructure the code a little bit:
function copy() {
var OriginalSheet = SpreadsheetApp.openById('Spreadsheet ID').getSheetByName('Sheet1')
var OriginalRange=OriginalSheet.getRange("A1:C"+OriginalSheet.getLastRow());
var DestinationSheet = SpreadsheetApp.openById('Spreadsheet ID').getSheetByName('Sheet2')
var DestinationRange=DestinationSheet.getRange("A1:C"+OriginalSheet.getLastRow());
DestinationRange.setValues(OriginalRange.getValues());
}
Careful:
This approach will only work if in the range the last row with content is indeed within the columns A:C.

Changing info on a different sheet in the same spreadsheet

I have two ranges of equal size on different sheets in the same spreadsheet. I am trying to find a row (based off of user input) in the first sheet and then use that index to modify a table in the second sheet that counts how many times that certain index has been used before (to make a nice looking pie chart).
This code runs but will not produce results on the second sheet. I've gone through the debugging process and my best guess is that for some reason, my for in loop is not running through. Attached is my code that takes in the beforementioned index and attempts to perform the second half of my goal.
function acceptToEncounterChart(ghostrow) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(ss.getSheets()[1]);
ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Average Encounter Chart");
var range = sheet.getRange("B3:B14")
for(var i in range) {
if(ghostrow == i) {
var before = range[i][0].getValue()
range[i][0].setValue(before + 1);
}
}
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]);
};
Explanation:
I am not entirely sure what is your goal.
However, here is some fixes / improvements starting from the beginning:
You define 2 times the same variable ss with exactly the same value.
You don't need to set the active sheet, if your goal is to just get the sheet, therefore this line is redundant:
SpreadsheetApp.setActiveSheet(ss.getSheets()[1]);
Variable range is not an array but a range object. You can't index it and therefore you can't also use a for loop to iterate over a single object. For the same exact reason, the code inside the if statement is wrong, you can't index range. But you don't see any errors because the if statement evaluates to false.
In JavaScript and in many other programming languages, array indexes start from 0. Since your range starts from cell B3 or row 3, you need to use i+3 to match the data with the range.
For the same reason as the previous point, ghostrow is an index, not a row. The if statement compares an array index i with ghostrow, so ghostrow should not be confused with the actual sheet row. For example, if you choose ghostrow=5 then the current script will increment the value of the cell B8 (remember i+3) by 1.
Solution:
Here is a workable code snippet:
function acceptToEncounterChart(ghostrow) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Average Encounter Chart");
var data = sheet.getRange("B3:B14").getValues().flat();
data.forEach((v,i)=>{
if(ghostrow == i){
sheet.getRange(i+3,2).setValue(v+1)
}
});
ss.setActiveSheet(ss.getSheets()[0]);
}
Related:
Please explore the official google apps script documentation.

setFormulas to a new spreadsheets when created

I have been searching through question and example everywhere but I can not seem to find an answer. I need to set these formulas in the header row and columns AQ:1 to AV:1(AQ1:AV1).
["={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}",
"={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}",
"={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}",
"={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}",
"={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}"],
and I need to put this into the second row of column AQ (AQ2).
["=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
I keep getting this error message and I cannot save the script.
Missing ] after element list. (line 138, file "Code")
I think I know why but I need the headers to be titled with the correct text because I use the headers in other functions.
function setFormulas(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This sets the formulas to be a row of sums, followed by a row of averages right below.
// The size of the two-dimensional array must match the size of the range.
var formulas = [
["={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}",
"={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}",
"={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}",
"={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}",
"={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}",
"={"Wages:";ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
["=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
];
var cell = sheet.getRange("AQ1:AW2");
cell.setFormulas(formulas);
}
Am I missing something or am I doing it completely wrong and need to find another way to do it. I also need to add the formulas to every sheet in the spreadsheet but I have not been able to test if it works. Thank you in advance for any help.
UPD:
It seems like double quotes are interfering here. To avoid this, you can use single quotes for formula enclosure and double quotes within formula, like this:
'={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}'
As mentioned in comments:
Arrays would expand so you are likely to need setting formulas in one row, like AQ1:AW1
Besides, if there's source data in columns AQ:AU (by the looks of formulas), setting array formulas in the same columns will most likely return error: Array result was not expanded because it would overwrite data in AQ18.
You seem to have an extra } at the end of the last formula
Try this and adjust to your needs:
function setFormulas(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This sets the formulas to be a row of sums, followed by a row of averages right below.
// The size of the two-dimensional array must match the size of the range.
var formulas = [
['={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}',
'={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}',
'={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}',
'={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}',
'={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}',
'={"Wages:";ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}',
'=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))']
];
var cell = sheet.getRange("AW1:BC1");
cell.setFormulas(formulas);
}

Issue applying script to second sheet

I have no idea how to code. I use to make website on HTML, so my knowledge is limited. I piece together and alter existing codes. I got decent on Excel VBA, but then needed to start using google sheets. So, that said...
I have a spreadsheet with two sheets, 'MIS' and 'Admin'. I have a bunch of code a formula that assigns a value (1,2,3...) based on how many of two drop-down criteria that each line matches (1 if it matches criteria #1, 2 if matches criteria #2, and 3 if it matches both). The code then hides everything and unhides only those with numbers matching the criteria. I need this to be clean and quick, it's for people who can barely use computers.
The problem is, the code only works on the first page. I tried using the same code, tried amending the code, and I tried inserting 'Admin' in about half a million places. Please help. The admin function is my latest attempt. This is where I inserted 'Admin' in a dozen places. Also, if you see anything I'm using that is slowing down the code, I could use some help with that too. There are 6 functions, which basically do the same thing using the same code but corresponding to different number combinations. The one in question is below.
function Admin(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets('Admin')[0];
var range = sheet.getRange(1, 1, sheet.getLastRow());
sheet.hideRows(8,sheet.getLastRow());
var values = range.getValues();
for (var i=0; i<values.length; i++){
if(values[i][0] === 3){
sheet.showRows(i+1);
}
}
}
This line is your 'only the first sheet' problem, you're sort of combining two methods of defining a sheet:
var sheet = ss.getSheets('Admin')[0];
You can get a specific sheet by name by using the .getSheetByName() method i.e.
var adm_sheet = ss.getSheetByName('Admin');
var mis_sheet = ss.getSheetByName('MIS');
Or you can get a sheet by index
var adm_sheet = ss.getSheets()[0]; //returns first sheet
var mis_sheet = ss.getSheets()[1]; //returns second sheet
Lastly, you can get all of the sheets in your spreadsheet and list them in an array like this:
var sheets = ss.getSheets();
And then use the index of the sheet you need in this array like so:
sheets[0] //the first sheet
sheets[1] //the second sheet