Automatically Detect New entry and create another new row - javascript

I have one google spreadsheet with two sheets that have same number of rows.
What I want to do:
When a new entry is written after the last row of Sheet1, it will automatically copy the last row of Sheet2 and paste it after that. (The new row will be in the last row after this, and both sheets will have same row again)
Since I don't use google script too much, I don't know how to accomplish it. Which functions or formula shall I use?
Thanks in advance.

You can use the onEdit() function, and the getLastRow() method, and copyTo()
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This logs the value in the very last cell of this sheet
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var lastCell = sheet.getRange(lastRow, lastColumn);
Logger.log(lastCell.getValue());
var lastRowAndCol = lastRow + ":" + lastRow;
var newRowOnEnd = (lastRow+1) + ":" + (lastRow+1);
Logger.log('lastRowAndCol: ' + lastRowAndCol);
Logger.log('newRowOnEnd: ' + newRowOnEnd);
sheet.getRange(lastRowAndCol).copyTo(sheet.getRange(newRowOnEnd));
};
Google Documentation - onEdit
Google Documentation - getLastRow
copyTo

Related

Cannot Read Property 'getSheetId' of null; Not sure why this happens

I have a the following snippet of code
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var driverArray = sheet.getRange("H2:H33").getValues().flat().filter(r=>r!="");
var ssname = ss.getName();
var length = ssname.length;
var shName = sheet.getName();
var date = ssname.substring(0,length-15);
var scheduleDate = ss.getSheets()[7].getRange("G27").getValue(); //this contains a formula, but it evaluates to a date coinciding with the title of a sheet
const body = "Hello, <br><br>Attached is the pay stub for the week ending "+ date+"."+"<br><br> Thank you, <br> Elizabeth";
var arrayLength = driverArray.length;
var scheduleSheet = SpreadsheetApp.openById("SpreadsheetURL");
var scheduleSS = scheduleSheet.getId();
var nextSchedule = scheduleSheet.getSheetByName(scheduleDate);
var scheduleID = nextSchedule.getSheetId(); // I believe the error is coming here
I am trying to get the ID of a sheet on a different spreadsheet. I believe that I am navigating to that sheet correctly, but I get the error "cannot read property of 'getSheetId' of null". Does this mean that it did not find a sheet with the name?
G27 contains the formula
=(Leftb(Summary!$A$2,2)&"-"&Midb(Summary!$A$2,3,2)&"-"&rightb(Summary!$A$2,2))+7
but it evaluates to a date. And the format of the date matches correctly with the title of the sheet.
Instead of
var scheduleDate = ss.getSheets()[7].getRange("G27").getValue()
use
var scheduleDate = ss.getSheets()[7].getRange("G27").getDisplayValue()
The above because getValue() returns a Date object for cells holding a date value and usually the Date object is parsed as string in a long format rather than the usual date formats.

Trying to Run two functions and two different emails in google scripts

I'm trying to have my sheet trigger an email alert when the last row on certain column matches an if statement after a google form feeds the sheet. it worked the first time but when i try to do a second condition it only acomplishes the second if. so separated the ifs work, but not combined.
can you guys help? here is the function:
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Observaciones Diarias IMPRG");
var lr = ss.getLastRow();
var currentTemp = ss.getRange(lr, 6).getValue();
var currentkidName = ss.getRange(lr, 3).getValue();
var currentTexture = ss.getRange(lr, 15).getValue();
if(currentTemp >39) {
MailApp.sendEmail("xxx25#gmail.com","Temperature>39°Alert", currentkidName + " had atemperature of " + currentTemp + "° " +" which is extremely high, please check")
}
else if (currentTexture = 1){
MailApp.sendEmail("xxx#gmail.com","Texture Alert", currentkidName + " had a " + " liquid Evacuation. which indicates an issue, please check")
}
}
currentTexture = 1 this is asigning a 1 to currentTexture. To do a comparison use
currentTexture == 1
or
currentTexture === 1
Related
Google Script checking that the data within one column on one sheet is the same as another column in another sheet
How do I find the cell with a certain background color, and set background of different cell in relation to it?
How to set a variable based on other variables
I'm trying to make an id searcher which does a thing when you input the right id. However, the if statement always runs. Why is this?

Creating a Google Calendar Event with Google Sheets script has Errors

I'm close, but my logic just isn't quite working. I am able to run the code below within Google Sheets Scripts to create a calendar event for each row in the sheet. I am trying to get it to only create an event when a new row is entered and to only read the spreadsheet until it comes to the first column/row being empty/null. enter image description here
Here is the associated code:
function createCalendarEvent() {
var sheet = SpreadsheetApp.getActiveSheet();
var calendar = CalendarApp.getCalendarById('dentaldigitaldesign.bkp#gmail.com');
var startRow = 100; // First row of data to process - 100 exempts my header row and adds to the case number count.
var numRows = sheet.getLastRow(); // Number of rows to process
var numColumns = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows-1, numColumns);
var data = dataRange.getValues();
var complete = "TRUE";
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var caseID = row[0]; //Case ID Number
var patient = row[4]; //Patient Name
var doctor = row[5]; //Doctor
var contact = row[14]; //Doctor contact info
var tooth = row[15]; //Tooth number
var shade = row[10]; //Tooth Shade
var notes = row[8]; //Notes
var callNotes = row[7]; //Call notes if there are any
var timeStamp = new Date (row[2]); //Retrieve the timestamp field
// year as 4 digits (YYYY)
var year = timeStamp.getFullYear();
// month as 2 digits (MM)
var month = ("0" + (timeStamp.getMonth() + 1)).slice(-2);
// date as 2 digits (DD)
var day = ("0" + timeStamp.getDate()).slice(-2);
var dueDate = new Date(month + day, + year); //Due date
var rDate = new Date(row[2]-1); //Remind date
var caseComplete = row[3]; //Case marked as complete
if (caseComplete !== complete && caseID !== null) {
var currentCell = sheet.getRange(startRow + i, numColumns);
calendar.createEvent(patient, rDate, rDate, {
description: doctor + '\r' + patient + '\r' + contact + '\r' + dueDate + '\r' + tooth + '\r' + shade + '\r' + notes + '\r' + callNotes
});
currentCell.setValue(complete);
}
}
}
When these events are created, they are all created for 8:59am. Ideally, I could do a check on the calendare if an event is set for that time, a new event is added immediately after. (perhaps in 15min or 30min slots). For now it works well for me to get the reminders on cases that are due, but eventually an invite to the doctor for them to know the due date might work well, too.
I can also use help in formatting the description field as it is not pushing the return value and everything is on one line.
And finally, the script continues to run on numerous fields beyond the scope of the desired rows, ultimately ending up with the script failing because too many event attempts are created in too short a time. (all the attempts with fields that are empty do not result in any events being created, but it is a resouce issue....and who knows maybe Google eventually blocks me?)
I appreciate any help that can be offered.
Here is the link to the Google Sheet. No data on it is sensitive as it is only test data: https://docs.google.com/spreadsheets/d/1M9qYzSl1PnRv-GehHEYvpiag15UI_GjnanA0wgA4xmg/edit?usp=sharing
There are several issues with your code, causing this expression to always return true, so that the script tries to create an event for each row:
if (caseComplete !== complete && caseID !== null) {
Empty string !== null:
You want to check whether the cell in column A is empty (that is, whether its value is an empty string), and to do that you are comparing its value to null. null is not the same as an empty string, so the following expression will always be true (a cell value never returns null):
caseID !== null
You should be comparing this to an empty string. For example, like this:
caseID !== ""
So the if statement should be:
if (caseComplete !== complete && caseID !== "") {
Wrong complete column:
Once an event has been created, you want to set the corresponding cell in D to TRUE. You're not doing that, since you specify the last column in the sheet (numColumns) when setting the currentCell:
var currentCell = sheet.getRange(startRow + i, numColumns);
Because of this, the value in D never changes to TRUE, so caseComplete !== complete is always true.
You should specify the correct column index for D instead, which is 4. It should be like this:
var currentCell = sheet.getRange(startRow + i, 4);
Edit: Also, the retrieved value for cell with checked checkboxes is the boolean true, and you're trying to compare it with the string TRUE. Because of this, this condition is not working correctly. Please change:
var complete = "TRUE";
To
var complete = true;
Wrong number of rows in source range:
You want to get the value from row 100 till the last one in the sheet. In this case, the total number of rows in the range should be the last row (numRows) minus the first row in the range (startRow) plus one (numRows - startRow + 1). The dataRange should be defined like this instead:
var dataRange = sheet.getRange(startRow, 1, numRows - startRow + 1, numColumns);
Reference:
Class Range
null

Google sheets, scripts stop working after making a copy.

I have a spreadsheet that I have built to be used as a template. This spreadsheet has a few scripts in it, the problem I am having is when you make a copy of the spreadsheet, all of my scripts stop working. I have to go into each script and manually authorize them again.
We would be making a copy of the Master spreadsheet for every single job that comes through my department. Roughly 20-30 copies of the master would be made each day, by multiple people.
Is there anyway to avoid this?
Please see sample code and spreadsheet below.
Thanks,
Tyler
https://docs.google.com/a/costco.com/spreadsheets/d/1vcmjVtS2mKwCGfboVFK14yNoksTJ7pq4vDcKIOpG2oU/edit?usp=sharing
function customDocEmail(){
var sheet = SpreadsheetApp.getActiveSheet();
if (sheet.getName() == "Version 1 ") {;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var triggerCell = sheet.getRange("C17").getValue().toString();
var email = sheet.getRange("A17").getValue().toString();
var EMAIL_SENT = new Date() ;
var recipients = "Youremail#gmail.com";
var cellA1 = ss.getSheetByName("Version 1 ").getRange("A1").getValue().toString();
var cellB2 = ss.getSheetByName("Version 1 ").getRange("B2").getValue().toString();
var cellD1 = ss.getSheetByName("Version 1 ").getRange("D1").getValue().toString();
}
var subject = 'New customDoc ' + cellA1+ '-' +cellB2;
var body = ' Hi Stephanie,' + '\n' + '\n' + 'This job ' + cellA1 + '-'+ cellB2+ ', is being created as a CustomDoc.. Please view the specs for this job. ' + '\n' + ss.getUrl() +' '+ '\n' + '\n' +'Thank you,' + '\n' + cellD1 +' ' ;
if (triggerCell =="YES")
{MailApp.sendEmail(recipients, subject, body);
sheet.getRange("C17").setValue("SENT");
}
}
function templateMagix() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Version 1 ");
var trigger = sheet.getRange("B3").getValue().toString();
var formNumber = sheet.getRange("A23").getValue().toString();
var boom = sheet.getRange("C23").getValue().toString();
if (boom =="BOOM")
sheet.getRange("B3").setValue(formNumber);
}
The reason why you have to authorize your scripts time and again is because each copy that you create is treated as a New Document and so are the scripts attached to that document. And for any new document to be able to run scripts, it is necessary for the user to provide that document permission to run scripts. Being able to make copies and run scripts without having authorized it manually will be somewhat similar to providing a script unauthorized access to run. Which, if it were possible, could be seen as a serious security thread. Therefore, unfortunately so, it is not possible to run scripts without providing them permission to run.
Although, depending on how many scripts you have, your use case and what function(s) they are performing etc., I would suggest that if it is possible combine these functions into one script and call them where necessary. This way, you will have to only provide manual permission to the script once instead of having to do it n number of times (assuming you have n scripts) for each script to be granted permission to run.
I was able to figure out a work around for this and it works flawlessly for my application.
I put all onEdit scripts in the same "Project", then I made a button and assigned my timeStamp Function to it. This prompted the authorization for all of my scripts that required the Auth.
Next I ran into all of the "installed onEdits" not staying installed upon making a copy of the spreadsheet, so the script's still were not functional. A little more digging and research brought me to writing a simple but effective script, that I assigned to my newly created button. Which in turn install's all of my onEdit triggers as well as prompting the authorization and all script's now work as they were intended.
I hope someone dealing with the same issues can find some use in this.
function authoRize(e) {
Browser.msgBox("Great! Let's be friends!");
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("customDocEmail")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("templateMagix")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("GetData")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("GetPJData")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeek")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeekOP")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeekPJ")
.forSpreadsheet(sheet)
.onEdit()
.create();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("HOME");
var newDate = new Date() ;
sheet.getRange("A5").setValue(newDate);
goToSheet('Version 1 ');
}

Adding to a Google Doc from a Google Spreadsheet Using Apps Script

I'm new to using the DocumentApp in Google Apps, so looking for some help!
I'm trying to create an FAQ (in a Google Doc) automatically from a spreadsheet. If certain conditions are met in the spreadsheet row, I want the script to find the category of the question in the document and insert a new question and response underneath it (pushing anything already there back).
So I'd have a document that looks like this:
https://docs.google.com/document/d/1fjb3RO6hUY6n7x0bu6WvtcleMWRNC8VQ9U82hXiGqcY/edit?usp=sharing
And a spreadsheet that looks like this:
https://docs.google.com/spreadsheets/d/1fb3ceqP6142_C7QQ1PfkWtVNswOyzOxkWCofvauf4Ps/edit?usp=sharing
And this is the code I'm trying to use. I'm getting a ton of errors- mainly because I don't have a good grasp on what the different elements involved are. Can anyone point me in the right direction?
function insertnewquestion() {
//(works fine)Get active document and related spreadsheet
var doc = DocumentApp.getActiveDocument().getBody();
var ss = SpreadsheetApp.openById("xxxxxxx");
var sheet = ss.getSheetByName("xxxxx");
//(works fine)Go through the various rows in the spreadsheet up to the last row
for (var row = 2; row <= sheet.getLastRow(); ++row) {
var status = sheet.getRange(row,4).getValue();
var question = sheet.getRange(row,1).getValue();
var response = sheet.getRange(row,2).getValue();
var category = sheet.getRange(row,3).getValue();
var date = sheet.getRange(row,5).getValue();
//(works fine)find rows with blank status and a response filled in
if (status !== "Entered" && response !== "") {
//(errors! this is where i need help) find the pertinent header
var categoryposition = body.findText(category); //looking for the category header- new text should be added after this, the idea is that what was already under this header will move down
var questionheader = categoryposition.appendText(question); //trying here to add in question text after where the category was found
questionheader.setHeading(DocumentApp.ParagraphHeading.HEADING3); //set question text as heading 3 (so it shows up on table of contents)
questionheader.appendText("\r"+"\r"+response+"\r\r"); //add line breaks and then the response text in normal font, then more line breaks to put space between new stuff and old stuff
//(works fine)Mark in the spreadsheet that it was entered in FAQ and the date so that it isn't double entered next time the script runs
sheet.getRange(row,4).setValue("Entered");
var currentTime = new Date()
var month = currentTime.getMonth() + 1
var day = currentTime.getDate()
var year = currentTime.getFullYear()
var date = (month + "/" + day + "/" + year)
sheet.getRange(row,5).setValue(date);
}
else {continue}
}
//(need help!) Refresh table of contents to include new questions
//no idea how to do this!
}
In the code you are referring to body.findText(category); where it should be doc.findText(category);. Also for the line:
var categoryposition = body.findText(category);
it returns the RangeElement — a search result indicating the position of the search text, or null if there is no match
Before adding any lines of code you have to check for null value in categoryposition.
The text class has a method to insert text in particular offset value to particular String value gives as shown here.
Hope that is helpful.

Categories

Resources