Trying to append rows what am I not grasping? - google-apps-script

Summary:
I need to get a range of values from one sheet, then set them into the first empty row of the second sheet. If that row is full, then append to the next.
I can get the script to set values into their corresponding cells, but not append; and I've been able to append a single cell value into an empty cell, but not the entire range. What am I not comprehending?
The goal:
Basically I'm taking user input (lets say race data) and saving it to another sheet for referencing later. (possibly to average race times by weight and height or something)
Research: I'm a bit new to this, but I've also done a good bit of research, such as ben collins free introductory course and other questions from here (just to name a couple):
[Get Range] SpreadsheetApp: getRange and setValues
[Copy Range] How to copy row ranges in Google docs?
Code
Grab my data:
const data1 = sheet1.getRange("A2:F2").getValues(); //grab data
Sets the range where I want it, but doesn't append:
sheet2.getRange("A2:F2").setValues(data1) //gets range and sets the value
So I've tried:
function r () {sheet2.getRange(newRow,1,1,data1.length).setValues(data1)};
return (r);
and even added:
sheet2.appendRow(data1);
(newRow is essentially getLastRow)
The above gives me a row of set values, then appends this in the following row: [Ljava.lang.Object;#f2a6014
-which in my research I've found what it is, but I don't understand why it happens.
I know I'm overlooking something or arranging something incorrectly but I cant figure out what it is that I'm not understanding.

Using your first two example I wrote this script and it works:
function copydata() {
const ss=SpreadsheetApp.getActive();
const sheet1=ss.getSheetByName('Sheet1');
const sheet2=ss.getSheetByName('Sheet2');
const data1 = sheet1.getRange("A2:F2").getValues();
sheet2.getRange("A2:F2").setValues(data1);
}
And this works also assuming that you realize that data1 is only a single row but it's still a two dimensional array so you have to use data1[0] to extract the single dimensional array from the two dimensional array
function copydatatofrom() {
const ss=SpreadsheetApp.getActive();
const sheet1=ss.getSheetByName('Sheet1');
const sheet2=ss.getSheetByName('Sheet2');
const data1 = sheet1.getRange("A2:F2").getValues();
sheet2.getRange("A2:F2").setValues(data1);
sheet2.appendRow(data1[0]);
}

Related

Need to Eliminate Rows where the Value column is blank, Google Sheets

I have a sheets document that I am unpivoting to make the data more readable. In its unpivoted form there are 6 headers, the last of which are Item and Value. I need to eliminate rows that do not have anything in the Value column.
Here is the equation that I am using.
=ARRAYFORMULA(split(flatten(transpose(query(transpose(Sheet1!A3:E20&"|"),,9^9))&"|"&Sheet1!F2:EU2&"|"&Sheet1!F3:EU20),"|"))
I have been able to take the table I get and use filter to create the table that I want, however, I need this all to happen in one equation as the computation time needed in the initial equation is already too long to process all the information. I am hoping that by filtering the results as they are made that it will also speed up the render time.
Here is the filter I have had success with:
=FILTER(A:G, G1:G<>"")
I am working with over 16,000 rows of data in the initial sheet.
The other strategy I am working on is using an apps script and macro to set the equation above in, set the filter, copy the filter table, paste it in another sheet, then go back, change the previous equation, and repeat. This strategy is also very slow.
Any advice is welcome. I am new to working with sheets so sorry if there is any obvious solution that I am missing.
Thank you for the help.
Delete rows where Value is blank
Assume one header row and data starts of row 2
function myfunk() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("SheetName");
const [hA,...vs] = sh.getDataRange().getDisplayValues();//assumed one header row and data start on row 2
const idx = {};
let d = 0;
hA.forEach((h,i) => {idx[h]=i;});
vs.forEach((r,i) => {
if(r[idx['Value']]=="") {
sh.deleteRow(i + 2 - d++);
}
});
}

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.

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.

getRange outputting "Range" instead of values

So, I'm making a code that copies certain data from our EOD worksheet, and copy/pasting the data onto another sheet, which acts as a summary.
I've got most of the code already working, but running into trouble with the getRange output. It just shows "Range" in the cell instead of my input, which should all be numbers.
function myFunction() {
var source = [];
var destSheet = SpreadsheetApp.getActive().getSheetByName('SnapshotSpreadsheet');
var destRange = destSheet.getRange(destSheet.getLastRow()+1,2);
source.push(sheet.getRange('B20'));
source.push(sheet.getRange('E20:F20'));
source.push(sheet.getRange('H20'));
source.push(sheet.getRange ('J20:I20'));
source.push(sheet.getRange ('M18'));
source.push(sheet.getRange ('K20'));
source.push(insertDate());
destSheet.getRange(2,1,1,7).setValues([source]);
I've included just the portion that is causing the issue. I defined source as an array, and stored values into the array, then just called for them to be output on the next available line. Everything seems to be lining up alright, just the values are all "Range".
You need to use getValue() (if single cell) or getValues() (if multiple cells) to get the content of those ranges.
Cfr https://developers.google.com/apps-script/reference/spreadsheet/range#getValue()
You'll need to do .getValues() for it to return the values of the cells
var values = sheet.getRange('E20:F20').getValues();
This returns a Two Dimensional array of values, so you'll have to work around that in your code. For example the line of code I just wrote would be an array like
[[Value at E20, Value at F20]]
so in order to access the Value at E20, you would call values[0][0] or for Value at F20, - values[0][1]

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);
}