How to Make Function Execute Formula on Last Row? - google-apps-script

I am trying to use the script editor to allow me to execute the function stored in cell A1 every 24 hours. I want the value that is generated to be stored in cell A2, then the next time the script runs I want that value stored in A3, and so it goes. The problem I am having is that I can't get my code to do this.
I have tried editing the last few lines of the script, but I can not get it to work.
function recordChanges() {
var url = 'LINK TO MY SHEET';
var ss = SpreadsheetApp.openByUrl(url);
var sh = ss.getSheetByName('Sheet1');
var range = sh.getRange("A1");
var values = range.getValues();
var lastRow = sh.getLastRow();
if (values[0][0] != values[1][0]) {
sh.insertRowAfter(lastRow);
sh.getRange().setValue(values[0][0]);
}
}
I expect the script to store the value, and the next time it runs I want it to store the value on the cell below the last store valued. Bonus points if you can get it to place the date the new value was generated in the same row but in column B.

getLastRow only returns the last row of the sheet that contains content.

I am interpreting your question as "how can I copy the value of A1 to the next empty cell in row 1?" My apologies if I am misinterpreting your question, please let me know.
It is unclear what you mean by "execute formula on last row"; please clarify and perhaps show the formula. This code does not make A1 change: I am assuming you already have the value of A1 changing somehow, and all you need to do is copy the current value to the end of row one.
function recordChanges() {
var url = 'LINK TO MY SHEET';
var ss = SpreadsheetApp.openByUrl(url);
var sh = ss.getSheetByName('Sheet1');
var range = sh.getRange("A1");
var firstRow = range.getDataRegion(SpreadsheetApp.Dimension.COLUMNS);
var values = firstRow.getValues();
values[0].push(values[0][0]);
sh.getRange(1, 1, 1, firstRow.getLastColumn() + 1).setValues(values);
}

Related

Google App Script to paste cell value to another spreadsheet based on column A and column header [duplicate]

sure I had this down but just can't get it right. Had a script set up to get data from one sheet and put it into another one, which I have done but it leaves gaps when copying and I can't figure out how to solve it. I'm sure in the code, its where I have put a question mark, is where the problem lies.
I have tried put i, last, last+1, 10, 12 but none of these work, feel like i'm missing something small to get this right. Below is the code a link to view the sheet if needed (the sheet is just for me to learn from, a basic example if you will).
Thanks in advance and also if the code could be better written, please just let me know as still learning this :)
function copyInfo() {
var app = SpreadsheetApp;
var copySheet = app.getActiveSpreadsheet().getSheetByName("Copy");
for (var i = 2; i <12; i++) {
var getInfo = copySheet.getRange(2,2,i,2).getValues();
// get the info from range above - start at row 2 on column 2 (b), get number of rows i , number of columns = 2, b,c
var last = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Paste").getLastRow();
var pasteSheet = app.getActiveSpreadsheet().getSheetByName("Paste");
// Tell it where you want the info to go to
pasteSheet.getRange(last+1,1,?,2).setValues(getInfo);
var clearIt = copySheet.getRange(2,2,i,2).clearContent();
// this clears the copy range aka getInfo
}}
link to sheet
You can copy whole range at once using copyTo, so your function could be rewritten as:
function copyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
// get source range
var source = copySheet.getRange(2,2,12,2);
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,2,12,2);
// copy values to destination range
source.copyTo(destination);
// clear source values
source.clearContent();
}

How to start autofill at last cell in one column to last row of adjacent column in Apps Script/Google Sheets?

So I have a table that will have data to the last row except column B. (for example, cols A, C, D etc. stop at row 40, but B stops at maybe row 25). I want to programmatically keep the series going starting at the last cell with data in B and autofill down to the last row in the spreadsheet. (Hopefully a script doing this will recognize the series and not just copy the same data to all the empty cells. When I do it manually it works.) I have something started here but I can't figure out how to call out the range of where to start the series. I get an error on line 7 "Exception: Range not found".
function fillDownFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var sc = ss.getRange("B1:B").getValues();
var scr = sc.filter(String).length;
var lr = ss.getLastRow();
var fillDownRange = ss.getRange(scr,2,lr)
ss.getRange(scr).copyTo(fillDownRange);
}
In addition to the answers already provided, Apps Script already has an autoFill() method that you can use to do this. With this you just have to define a source and a destination range. This works the same as selecting the range and dragging down your mouse manually on the corner.
function fillDownFunction() {
var ss= SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var lastsheetrow = ss.getLastRow() //last row with data
//last row in the autofill range with data
var lastrangerow = ss.getRange("B1:B").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow()
var sourcerange = ss.getRange(2, 2,lastrangerow-1) //in your screenshot, this would be B2:B6
var destinationrange = ss.getRange(2, 2, lastsheetrow-1) //This would be B2:B12
sourcerange.autoFill(destinationrange, SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES)
}
Note that I skipped the header row and offset the range lengths by -1 to compensate. This is because the autofill logic uses the entire range, so it would also take into account "Item2" and repeat it every 6 rows as "Item3", "Item4" and so on. A disadvantage in this case, but may prove useful if you plan to use autofill in more complex ways in the future.
Here is one way you could have the last fill value copy down. The function grabs all of the values, maps the row that needs to fill down and then copies that last value down the rest of the sheet.
function fillDownFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tab = ss.getActiveSheet();
var sc = tab.getDataRange().getValues();
var lastRow = sc.length;
var values = sc.map(function(r) { return r[1]; }).filter(i => i);
var lastFillRow = values.length;
var fillDownValue = values.slice(-1);
tab.getRange(lastFillRow + 1, 2, lastRow - lastFillRow).setValue([fillDownValue]);
}

Copy/paste values every day under previous pasted cell?

Here's my problem : i'm trying to copy a value from one cell in "sheet1" to another cell in "sheet2".
But I want to run this script everyday (using trigger) because the value change every day. So the paste has to be in B2 the first day, B3 the second day, etc. I want to be able to follow the value day by day and have an historic.
Here's my current script :
function backup(){
var sourceSheet = "Portfolio" ;
var sourceRange = "N15" ;
var targetSheet = "Suivi perfs journalières" ;
var targetRange = "B2:B999" ;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sourceSheet);
var values = sheet.getRange(sourceRange).getValues();
ss.getSheetByName(targetSheet).getRange(targetRange).setValues(values);
I have 2 problem :
My script send me this error : Exception: The number of rows of data does not match the number of rows in the range. There are 1 lines of data, but the range has 998. (line 12, "CopyPastePortfolioValue" file)
I don't know how to paste the value in a new cell everyday (paste in the cell under the previous each day)
Thanks for your help!
I believe your goal as follows.
You want to retrieve the value from the cell N15 in the source sheet and append the value to the target sheet.
Modification points:
When setValues(values) is used, the lengths of rows and columns of values are required to match to the range. In your script, values of var values = sheet.getRange(sourceRange).getValues(); is 1 row and 1 column. But the target range is B2:B999. By this, such error occurs. I think that this is the answer for your 1st question.
In order to append the value to the target sheet, in your case, I would like to propose to use appendRow. I think that this is the answer for your 2nd question.
And, when a value from a cell, you can also use getValue instead of getValues.
When above points are reflected to your script, it becomes as follows.
Modified script:
function backup(){
var sourceSheet = "Portfolio";
var sourceRange = "N15";
var targetSheet = "Suivi perfs journalières";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sourceSheet);
var value = sheet.getRange(sourceRange).getValue(); // Modified
ss.getSheetByName(targetSheet).appendRow([value]); // Modified
}
References:
setValues(values)
appendRow(rowContents)

Validating specific string in Google App Script

Situation:
Hi all! I have a Google Spreadsheet which contain two tabs ("Today" and "Current") and I want to validate the values in the cell of last row and column C in "Today" tab (such as C50 or C100, the row number may change) is it equal to the string of "ERROR". If this cell contain the string "ERROR", it will copy the data in the cell of A2:J2 from "Current" tab and replace the "ERROR" string in "Today".
Problem:
Hence, I typed the following code and now it can get the values in "Today" but it failed to validate whether it contains "ERROR" or not. May I know what's wrong with my code? Thank you!
Code:
function checkdata(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Today');
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var data = sheet.getSheetValues(lastRow,3,1,1);
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var sheet2 = ss2.getSheetByName('Current');
var values = sheet2.getRange("A2:J2").getValues()[0];
if (data) {
if (data.indexOf('#ERROR!') < 0) {
sheet.getRange(lastRow+1, 1, 1, 10).setValues([[].concat(values)]);
}}}
Modification point:
getSheetValues() returns 2 dimensional array. In this script, the if statement is always true. I thought that this might be the reason of your issue.
Modified script:
From:
var data = sheet.getSheetValues(lastRow,3,1,1);
To:
var data = sheet.getRange(lastRow, 3).getValue();
getValue() returns an object which is not an array. For example, when the value of cell is the string value, the string value is returned. By this, I think that the if statement works.
References:
getSheetValues()
getValue()
May I know what's wrong with my code?
A few issues:
If you want to replace the ERROR string, you need to copy the data from Current into the row where ERROR is located (the last row), not the row beneath it. So:
sheet.getRange(lastRow, 1, 1, 10).setValues([[].concat(values)]);
#ERROR! and ERROR is not the same, so review your situation to decide which is the string you are looking for (if your cell content is #ERROR!, you can find ERROR within it, but not the opposite
sheet.getSheetValues(lastRow,3,1,1); will return you a 2-D value range. In order to use the method indexOf, you need to address a single value of this value range, e.g. data[0][0].indexOf
Alternatively: Define var data = sheet.getRange(lastRow,3,1,1).getValue(); which will directly return you the value, not the value range
The method indexOf is defined in such a way that it return -1 if the value is not found and the position of the value (which is bigger than -1) if the value is found.
So, you need to change indexOf('#ERROR!') < 0 to indexOf('#ERROR!') >= 0
Sample:
function checkdata(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Today');
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var data = sheet.getSheetValues(lastRow,3,1,1);
var sheet2 = ss.getSheetByName('Current');
var values = sheet2.getRange("A2:J2").getValues()[0];
if (data) {
if (data[0][0].indexOf('#ERROR!') >= 0) {
sheet.getRange(lastRow, 1, 1, 10).setValues([[].concat(values)]);
}}}

Copy a row with specific cells to another spreadsheet

I have been searching for a way to copy certain cells from a row and paste them into another spreadsheet, but all I can seem to find are ways to do that just from sheet to sheet within one spreadsheet or questions that deal with code way above my head. I'm just now learning to code in Google Spreadsheets and I can't seem to get it right. Here is my code for now, I'm working on just copying one cell first and after I can do that I'll get a loop to iterate through the row and pick the cells I want to copy.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var master = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c');
var target = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c');
var master_sheet = master.getSheetByName("Steve2");
var target_sheet = target.getSheetByName("Corbin1");
var master_range = master_sheet.getRange("A1");
var target_range = target_sheet.getRange("A1");
master_range.copyTo(target_range);
Right now it is giving me an error saying that it cannot call the getRange method of null. I'm not sure if I'm using OpenById correctly or if I can even use that in this situation.
OK I've got it working now. It copies the row perfectly and it copies only the cells I want. Now I need help with the pasting part. It copies everything fine and puts it into the other sheet great, but I need it to copy into the next available row and into the first available columns. So if row 5 is the last column of data, I need it to paste into row 6 and take up the first 6 or so columns.
This is what I have so far.
function menuItem1() {
var sss = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c'); // sss = source spreadsheet Steve2
var ss = sss.getSheetByName('Sheet1'); // ss = source sheet
//Message box asking user to specify the row to be copied
var answer = Browser.inputBox('What row would you like to copy?');
var range = parseInt(answer);
var array = [1,2,3,9,12,30];
//Runs a loop to iterate through array, using array elements as column numbers
for(var i = 0; i < array.length; i++){
var SRange = ss.getRange(answer,1,1,array[i]);
//get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
//get the data values in range
var SData = SRange.getValues();
}
var tss = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c'); // tss = target spreadsheet Corbin1
var ts = tss.getSheetByName('Sheet1'); // ts = target sheet
//set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
//Confirmation message that the row was copied
Browser.msgBox('You have successfully copied Row: ' + answer);
}
You are getting this error maybe because your spreadsheet does not have a sheet called Steve2 or Cobin1. Try using the method master.getSheets()[0], this way you will get the first sheet without using their name.
You can algo use this piece of code to check the sheets names:
for(var x in master.getSheets()) {
Logger.log(master.getSheets()[x].getSheetName());
}
best,