Insert Comment - GoogleSpreadsheets - google-apps-script

I'm looking to insert comments onto a certain cell once a script has run.
The script I am using is to insert a calendar entry - however I only want it to do this once. To do this, I will get the script to check if a comment/note is entered onto the cell. In theory, this should be easy but I'm having trouble making it select the right cell... Can anyone help? My code is below.
I'm after the comment to go in the cell that corresponds with var = date.
If anyone can give me pointers, I'd really appreciate!
Cheers,
Pete
function CalendarInputIVNShortlist() {`
`var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 26); //What data will be used
var data = dataRange.getValues();
var cal = CalendarApp.getDefaultCalendar(); //Gets the correct calendar
for (i in data) {
var row = data[i];
var title = row[1]; // Column with Title
var desc = row[15]; // Column with Next Steps
var date = row[5]; //Column with Date
var invite = row[2] //Column with PDC Chairs & IVN Owner
var sent = row[12] //Check Sent
sheet.getRange(data[i], 5).setNote(Sent)
cal.createAllDayEvent(title, new Date(date), {description:desc,guests:invite});
var Comment = dataRange(date).setNote("Inputted")

There's a problem here:
sheet.getRange(data[i], 5)
The first parameter you've used, data[i], is an array (that you've already equated to row a few lines earlier). The getRange() method variance you are looking for expects two Numbers as parameters. If your intent was to add a note to column 5 of the row currently being references in your loop, then you want:
sheet.getRange(i+startRow, 5).setNote(sent);
Another issue with that particular line is with Sent; I assume you wanted to reference the variable you has set equal to row[12], just above, which had a small letter 's' in its name.
Next, there's something wrong here:
var Comment = dataRange(date).setNote("Inputted")
What is dataRange()? Unless it's another function in your script, that returns a Range object relevant to the contents of row[5], I would guess you intended this:
sheet.getRange(i+startRow, 5).setNote("Inputted");

sheet.getRange() needs 2 integers as parameters : the row number and the column number.
In your code you are trying to assign an array (data[i]) as row nuber...this cannot work.
Since it counts from startRow and since array are 0 indexed I would suggest you try like that :
sheet.getRange(startRow+i, 5).setNote(Sent)

Related

Google Appscript: Copy Data from a Form Sheet to Another Sheet in Last Row and Clear Form

Trying to get an Appscript to run but I can't seem to figure out the last few steps.
Background: I have a Google Sheet with two tabs, #1 is called "Data Form" which hosts a fillable form to capture Transaction information to then be input onto tab #2 called "Posted Transactions". This is a personal budget spreadsheet..
Anyways, The script below is intended to take the information input on the "Data Form", verify what the last row with data is on the "Posted Transactions" tab based on whether or not Column A has any data. (To further clarify, the "Posted Transactions" tab has formulas in columns G-I which prohibits me from using a simple "Find last Row" script.)
As it is written now, I receive an error "Exception: The number of columns in the data does not match the number of columns in the range. The data has 6 but the range has 1.
RecordNewTransaction # Code.gs:24"
Any suggestions to make this work properly?
UPDATE:
var dataRange = datasheet.getRange(lastRow+1,1,1,datasheet.getLastColumn()-3);
After many attempts at trial and error, I needed to edit the line shown above. Current & full script is performing as expected now and is shown below. Image snips of what I was trying to accomplish are also shown for reference.
function RecordNewTransaction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Data Form"); //Form Sheet
var datasheet = ss.getSheetByName("Posted Transactions"); //Data
//Input Values
var values = [[formSS.getRange("B4").getValue(),
formSS.getRange("B6").getValue(),
formSS.getRange("B8").getValue(),
formSS.getRange("B10").getValue(),
formSS.getRange("B12").getValue(),
formSS.getRange("B14").getValue()]];
var columnToCheck = datasheet.getRange("A:A").getValues();
var lastRow = getLastRowSpecial(columnToCheck);
Logger.log(lastRow);
var dataRange = datasheet.getRange(lastRow+1,1,1,datasheet.getLastColumn()-3);
Logger.log(dataRange);
var dataValues = dataRange.getValues();
Logger.log(dataValues);
dataRange.setValues(values);
Logger.log(dataRange.setValues(values))
formSS.getRange('B4:B14').clearContent();
};
function getLastRowSpecial(range){
var rowNum = 0;
var blank = false;
for(var row = 0; row < range.length; row++){
if(range[row][0] === "" && !blank){
rowNum = row;
blank = true;
}else if(range[row][0] !== ""){
blank = false;
};
};
return rowNum;
};
Try
var dataRange = datasheet.getRange(lastRow,1,values.length,values[0].length)
replace 1 as necessary (this is the firts column where the data will be stored
Reference:
getRange(row, column, numRows, numColumns)
See edited question above which contains the revised script needed.
The problem here was that columns G-I of my results sheet contain formulas (shown in grey) which required this line below to be modified to grab the last column -3, otherwise the script was looking at too many columns that it didn't need to. Also had to modify "lastRow" to "lastRow+1" because this kept overriding the very last line of data I already had input and the +1 will make new data go to the next available row.
var dataRange = datasheet.getRange(lastRow+1,1,1,datasheet.getLastColumn()-3);

Range Length in Google Apps Script

I want to run a script that copies a sheet data to a master sheet (append all my sheets).
The first part of copying and pasting is working but I want to add a column which tells me the name of the origin sheet. I wrote a loop for it but nothing is happening when I executing the script (only the copy and paste). This is my whole code:
function appendSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var reportLastRow = sh.getLastRow()
var reportLastColumn = sh.getLastColumn()
var reportData = sh.getSheetValues(3,1,reportLastRow,reportLastColumn);
var recordsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("2020 Data");
var lastRow = recordsSheet.getLastRow();
//var recordLastRow = sh.getLastRow();
var recordLastColumn = recordsSheet.getLastColumn();
var reportSheetName = sh.getSheetName();
recordsSheet.getRange(lastRow + 1,1,reportLastRow,reportLastColumn).setValues(reportData);
var arrayLength = (lastRow - reportData.length);
for (var i = 0 ; i <= arrayLength ; i ++) {
var taskDateCell = recordsSheet.getRange(arrayLength - i, recordLastColumn);
taskDateCell.setValues(reportSheetName);
}
}
Your code has several problems you should fix
Be aware of the fact that the method getRange() expects the syntax firstRow, firstColumn, numRows, numColumns - not firstRow, firstColumn, lastRow, lastColumn. You need to adjust your range and your function getSheetValues() (I assume it is you custom funciton based on the method getRange() accordingly.
If you assign a value to one cell at a time taskDateCell, you should use setValue() instead of setValues()
It seems like your definition of arrayLength might not be right. Test it by logging it.
Your main problem:
You define:
for (var i = arrayLength ; i < arrayLength ; i ++)
In other words:
Set i to arrayLength and iterate while i is smaller than arrayLength.
This condition is never fullfilled, and thus the number of iterations will be zero.
As a genral advice: Implement in your code many logs - to visualize important values, such a range notations and length of arrays, or counter variables in a loop - this will help you to find bugs faster.
Explanation:
First of all I optimized your code. You have unnecessary lines of code which make your code difficult to be understood but also slow. The optimizations involve reducing the number of lines to the minimum, defining constant variables, making the variable names more descriptive and finally getting rid of the for loop by replacing it with a more efficient approach.
Another correction would be at this line: sh.getSheetValues(3,1,reportLastRow,reportLastColumn); Here you are starting from the third row but you are getting two rows extra; reportLastRow is the number of rows you want to get but since you are starting from the third row you need to deduct 2.
To answer your question, one way to solve your problem is to set the name of the report to the last column of the records sheet where you entered the data from the report sheet. Since you want to add the same value (sheet name) to every row, you can select a 2D range but use setValue.
I am not a big fan of getActiveSheet in const report_sh = ss.getActiveSheet(); since this line is assuming that you have selected the desired sheet (report sheet) in the UI. Please be careful with that, otherwise change that line to something like that:
const report_sh = ss.getSheetByName('report sheet');
and of course adjust 'report sheet' to the name of the sheet you want to append.
Solution:
function appendSheet() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const records_sh = ss.getSheetByName("2020 Data");
const report_sh = ss.getActiveSheet();
const reportData = report_sh.getSheetValues(3,1,report_sh.getLastRow()-2,report_sh.getLastColumn());
const records_lr = records_sh.getLastRow();
records_sh.getRange(records_lr+1,1,reportData.length,reportData[0].length).setValues(reportData);
SpreadsheetApp.flush();
records_sh.getRange(records_lr+1,records_sh.getLastColumn()+1,reportData.length,1).setValue(report_sh.getSheetName());
}

String ranges in Google Apps Script

I have a sheet that I need to get values from and set in a new sheet, one of these values requires me to slice string value at indices 20,26. I can achieve this using .getValue().slice(20,26) and .setValue(). However, the same data is set in all rows, which is to be expected since I am only getting a single cell of data. To resolve this I tried a for loop which failed.
When I attempt .getValues().slice(20,26) it returns an empty array which throws the following error: The number of rows in the data does not match the number of rows in the range. The data has 0 but the range has 20.
My code is below and I welcome any guidance.
function pj() {
// Get Active spreadsheet.
var sheet = SpreadsheetApp.getActiveSpreadsheet();
//Get last row processed and update
var startRow =sheet.getSheetByName("Index").getRange("A1").getValue();
startRow++;
// Get payments sheet.
var paymentSheet = sheet.getSheetByName("Payments");
var clientSheet = sheet.getSheetByName("Client Details");
var lastRow = paymentSheet.getLastRow();
//Inputs
var firstName = paymentSheet.getRange(startRow, 3, (lastRow-startRow+1), 1).getValues();
var lastName= paymentSheet.getRange(startRow, 4, (lastRow-startRow+1), 1).getValues();
var paymentId = paymentSheet.getRange(startRow, 14, (lastRow-startRow+1), 1).getValues().slice(20,26);
}
//Outputs
clientSheet.getRange(2,1,(lastRow-startRow+1),1).setValues(firstName);
clientSheet.getRange(2,8, (lastRow-startRow+1),1).setValues(paymentId);
//Update the last row processed
sheet.getSheetByName('Index').getRange("A1").setValue(lastRow);
}
Please see image of the sheet I am working with, as you will see column N contains a payment ID, which holds a unique identifier for the client that I need to extract in order to upload this data into Salesforce. It seems the issue is that Logger.log is reporting the string correctly as it goes through the array, but is reporting the length as 1. I've tried changing the format of that column various ways, Text, Number etc but it doesn't seem to make any difference to the reported length. I'm assuming this is why the split function isn't working, but I'm not sure why it's happening?Sheet
I guessed at a lot of this but it should look similar to this:
function pj() {
var ss=SpreadsheetApp.getActive();
var isht=ss.getSheetByName("Index");
var startRow=isht.getRange("A1").getValue()+1;
var psht=ss.getSheetByName("Payments");
var csht=ss.getSheetByName("Client Details");
var lastRow=psht.getLastRow();
var prg=psht.getRange(startRow,1,psht.getLastRow()-startRow+1,14);
var pvals=prg.getValues();
pvals.forEach(function(r,i){
csht.getRange(i+2,1).setValue(r[2]);
csht.getRange(i+2,2).setValue(r[3]);
csht.getRange(i+2,8).setValue(r[13].slice(20,26));
});
isht.getRange("A1").setValue(csht.getLastRow());
}

Copy a variable range depending on the number of non-empty cells

From a google sheets macro, I am trying to copy a variable range of cells, which depends on the amount of non-empty cells each time. In the following sentence:
spreadsheet.getRange ('Orders! 1: 30'). copyTo (spreadsheet.getActiveRange (), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
I need that instead of the number "30" there is a variable that is defined according to how many lines are occupied in column I of the same sheet.
I was thinking of using the "for" function to scan lines in column I from the cell I1 until It finds an empty one (or not greater than 0). but I'm not sure how to do this.
After the help of #Iamblichus and #Tedinoz I was able to advance in the code, but now a connected and similar problem arised.
I need to paste the selected range in a different tab, but in which same variable no longer recognizes same amount. This is my code:
function Test() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName("Aux");
spreadsheet.getRange('I3:I').createFilter();
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(['0']).build();
spreadsheet.getActiveSheet().getFilter().setColumnFilterCriteria(9, criteria);
var valuesI = spreadsheet.getRange("I1:I").getValues();
var numRowsI = valuesI.filter(String).length;
var firstRow = 1;
var firstCol = 1;
var numCols = sheet.getLastColumn();
var originRange = sheet.getRange(firstRow, firstCol, numRowsI, numCols);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Hist_D'), true);
spreadsheet.getActiveSheet().insertRowsBefore(sheet.getActiveRange().getRow(), numRowsI);
spreadsheet.getRange('A1').activate();
originRange.copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_FORMAT, false);
originRange.copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Aux'), true);
spreadsheet.getRange('T35').activate();
spreadsheet.getActiveSheet().getFilter().remove();
}
"Hist_D" is a record in which the latest data is added at the top. I need to copy a variable amount X of lines from the "Aux" tab to the first lines of the "Hist_D" tab. But before that I need to add (insertRowsBefore) the same number X of lines in "Hist_D" so that the old info is not overwritten. My problem now is how to keep the amount X in the numRowsI variable when changing tabs.
The number of lines inserted through the formula .insertRowsBefore is around 100 (total number of lines in the first tab), when it should be around 20 (number of non-empty lines in the first tab). According to my interpretation, for some reason the variable numRowsI changes when changing tab.
Update:
Assuming that:
For each row to be copied, you want to copy all columns with content and not just column I.
You want to copy this to the top of another sheet, without overwriting previous data.
You can try using this:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var originSheet = ss.getSheetByName("Aux");
var destSheet = ss.getSheetByName("Hist_D");
var valuesI = originSheet.getRange("I1:I").getValues(); // As far as I can see, you want to check column I, not B
var numRowsI = valuesI.filter(String).length;
var firstRow = 1;
var firstCol = 1;
var numCols = originSheet.getLastColumn();
var originRange = originSheet.getRange(firstRow, firstCol, numRowsI, numCols);
destSheet.insertRows(1, numRowsI);
var destRange = destSheet.getRange(firstRow, firstCol, numRowsI, numCols);
originRange.copyTo(destRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES);
}
The main thing here is finding the last cell with content in a specific column, something that can be achieved using this (assuming there are no blank cells in between, which, considering your question, seems to be the case).
The number of blank rows you have to add to the top Hist_D in order not to overwrite existing data equals the number of rows that have been copied from Aux (that is, equal to numRowsI). You are having problems because getRange is a method of the Sheet class, not the Spreadsheet class.
I hope this is of any help.
Props to #Mogsdad ref and AndyE before him, for this incredibly handy method.
var Bvals = ss.getRange("B1:B").getValues();
var Blast = Bvals.filter(String).length;
The value of "Blast" is the number of cells in Column B that contain values - there is an implicit assumption that it is a contiguous range.
If you define your range using getRange(row, column, numRows, numColumns), then substitute "Blast" for "numrows".

How to send email from a spreadsheet

I have a spreadsheet on Google Docs with tasks for a job that we are working on at work. What I am wanting it to do is to send the whole row to the intended recipient but I can only get it to send the info from the first column after the email address. Everything has a due date on it and I would like to get it to send a reminder when it gets close to that date but I do not know how to do that.
Any help would be greatly appreciated.
Here is the code I have right now:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 3; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Column B, Column C, Column D, Column E, Column F, Column G
var subject = "Email Test Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
}
}
when you define your dataRange like this :
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
you read data from startRow column 1 for numRows but only 2 columns (the last value is 'width') so you could easily modify your script to get all the columns you want just by changing this last value. Then using row[i].toString(), you will get your comma separated fields.
Then you might want to get a better presentation using HTML format to present data in a table for example but this is outside the point of your question ;-)
When you define a data range like this
var dataRange = sheet.getRange(startRow, 1, numRows, 2);
you are taking the data from A3:C5
you can also refer to the documentation
If you can post a sample spreadsheet as per the description of your problem, then it will be helpful for others to help you.
This piece: var message = row[1]; will only ever get the second element (index 1) in the array. You'll need to iterate through the row to get all the array elements.
var message = row[1];
message.concat(row[2]);
message.concat(row[3]);
And so on. Or you could build a loop.
http://www.w3schools.com/jsref/jsref_concat_string.asp
And to get the range, why do it the hard way? sheet.getRange("A2:B3");
That's the range you said you're trying to get in the comment above that line, although it is only 4 cells. sheet.getRange("A2:G3") would get two rows out to column G.
Of course, if you add rows to the sheet, you'd have to modify the code every time.
Instead, try this.
var bottomRow = sheet.getLastRow();
var rangeInA1 = "A2:G"+bottomRow;
var dataRange = sheet.getRange(rangeInA1);