I have this web app in Appscript that receives info from a POST request from Siri Shortcuts.
function doPost(e) {
//Get active spreadsheet and input database tab name.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Test02');
if(typeof e !== 'undefined')
//Retrieve data received and make a string.
var data = JSON.stringify(e);
//1st print. Print string on new row.
sheet.getRange(sheet.getLastRow()+1,1).setValue(data);
//Eliminate all special characters coming from Siri Shortcuts POST request.
data = data.replace(new RegExp(["\\\\"], 'g'), "");
data = data.replace(new RegExp('"', 'g'), "");
data = data.replace(new RegExp("{", 'g'), "");
data = data.replace(new RegExp("}", 'g'), "");
data = data.replace(new RegExp(":", 'g'), "");
//Split all info on the left side of the first parameter and on the right side of the second.
data = data.split('Log')[1];
data = data.split("name")[0];
//2nd print. Print clean string on a new row.
sheet.getRange(sheet.getLastRow()+1,1).setValue(data);
//3rd print. Print all array element on row. End goal is to have them start from column A and keep adding 1 column every loop.
//Split string into array.
var dataArray = data.split(",");
var lastRow = sheet.getLastRow()+1;
for(var i = 0; i < dataArray.length; i++) {
//3rd print, first part. This tests the real data.
sheet.getRange(lastRow,1+[i]).setValue(dataArray[i]);
//3rd print, second part. This tests the index number to try and find why row are being skipped.
sheet.getRange(lastRow+1,1+[i]).setValue([i]);
}
//Use Mail app to send mail after completion.
MailApp.sendEmail("abc123#gmail.com","InningLogger - Test", data);
return;
}
Attached is the result I am getting in the spreadsheet.
I have two problems with rows 3 and 7:
Why is the data not starting from column A?
Why is row 7 skipping a ton
of columns (I hid them for the screenshot) to print the last 3
values?
Thanks!
As #Pointy mentioned, the problem lied within the 1+[i] in the for loop. "Because i is a number in your code, say 3, 1+[i] will be the string "13", not a number. Changing this to [i+1] solved the problem completely.
Related
Been building a landing page to start an email list. Decided to use Google Sheets as the backend to store emails & Google Scripts to send the first welcome message.
I hooked up an HTML page to Google Sheets with an API. The user submits their name & email, and then it goes to the Google Sheets. When the document is edited, this function gets triggered which sends a welcome message.
To prevent duplicate messages from going out, I put a simple system in place. When a user has been emailed, the third row (C) is filled in with "EMAIL_SENT" automatically.
When the function is triggered, it should only send the user an email if if there is no "EMAIL_SENT" but every time a new user submits their info, every single email on the list gets another welcome message.
I will attach an image of the spreadsheet
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'EMAIL_SENT';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow();
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 3);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var nameThisMan = row[1]; // Person's name
var emailSent = row[2]; // Third column
if (emailSent !== EMAIL_SENT) { // Prevents sending duplicates
var message = "Hey there " + nameThisMan + "," + "\n \n Thanks for joining the email list! You’re about to be getting some AMAZING programming resources. Here’s the link to the top 10 open source Github repos PDF. \n https://www.dropbox.com/s/wm8ctsdojlsoss6/10%20Most%20Useful%20Open%20Source%20Repos%20for%20Developers.pdf?dl=0\n\n And here’s the link to the archive of all the resources from this email list. These are from all past emails. \n https://docs.google.com/document/d/1hWmGNYkn0czRI29JJu9HgUVC6L4AsNYBxwt45ABnT6w/edit?usp=sharing \n \n Thank you again for joining the list! I will do my best to give you absolutely amazing programming resources. \n \n best, \n Michael Macaulay, Techtime.";
var replyTo = "TechTimeDev#gmail.com";
var subject = "Welcome to TechTime's Email List";
MailApp.sendEmail(emailAddress, replyTo, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
function sendEmails2() {
var sheet=SpreadsheetApp.getActiveSheet();
var startRow=2;
var numRows=sheet.getLastRow()-startRow+1;
var dataRange=sheet.getRange(startRow, 1, numRows, 3);
var data=dataRange.getValues();
for (var i=0; i < data.length; ++i) {
var row=data[i];
var emailAddress=row[0];
var nameThisMan=row[1];
var emailSent=row[2];
var replyTo="TechTimeDev#gmail.com";
var subject="Welcome to TechTime's Email List";
if (emailSent!='EMAIL_SENT') {
var message="Hey there " + nameThisMan + "," + "\n \n Thanks for joining the email list! You’re about to be getting some AMAZING programming resources. Here’s the link to the top 10 open source Github repos PDF. \n https://www.dropbox.com/s/wm8ctsdojlsoss6/10%20Most%20Useful%20Open%20Source%20Repos%20for%20Developers.pdf?dl=0\n\n And here’s the link to the archive of all the resources from this email list. These are from all past emails. \n https://docs.google.com/document/d/1hWmGNYkn0czRI29JJu9HgUVC6L4AsNYBxwt45ABnT6w/edit?usp=sharing \n \n Thank you again for joining the list! I will do my best to give you absolutely amazing programming resources. \n \n best, \n Michael Macaulay, Techtime.";
MailApp.sendEmail(emailAddress, replyTo, subject, message);
sheet.getRange(startRow + i, 3).setValue('EMAIL_SENT');
}
}
}
The method getLastRow() will return you the index of the last row with content. In the example you have provided this would be 3. However, what you actually want for performing getRange() is the number of rows you need to take. If you use three you would be taking an extra empty row and therefore, you would be getting the wrong values.
To change this to get the number of rows you need, you can simply do:
var numrows = sheet.getLastRow() - 1; instead of var numRows = sheet.getLastRow();
as you need to subtract from the index the number of rows you are not wanting to get in your range (in your case as you are ignoring the first row only 1 needs to be subtracted).
In using this tutorial script from: https://developers.google.com/apps-script/articles/sending_emails
I am new to apps script and have been searching the forums trying to figure this out...
I'm trying to use another column in the spreadsheet to dynamically enter the salutation in the message. I thought it would be a formula like this:
="Dear "E2, + "Our 2018 Catalog is Coming Soon! Would you like a copy? " But, then I get the error that -ADD parameter1 is text and it is looking for numbers-, (even though I found it in another help area to use the quotes to separate the cell references).
So my questions:
1.Is it possible to make dynamic changes to the message in this script? Or do I need another script in the message column to do this?
2.If I am running more than one script on the spreadsheet and connected form do I need separate script files or just separate blocks on the same file
Thank you!
Adding a separate salutation to an email script
Here's the script for that tutorial:
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // 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, 3)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Second column
var emailSent = row[2]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
I believe you wish to have a separate salutation which is at the beginning of the message portion. It appears that you also wish to use column 5 for that data.
So if that's the case then your message would be something like this:
var message = Utilities.formatString('Dear %s\n%s',row[4],row[1]); Reference
This could also be accomplished this way:
var message = 'Dear ' + row[4] + '\n' + row[1];Reference
In either case you would put a name in column 5 and the rest of your message in column2. If you wan't to use html in your email replace the '\n' (line feed) with '<br />' (line break);
The message starts with the saluation in row[4] (column 5) and the rest of the message comes from row[1] according to the tutorial which is column 2.
The data from a getValues() command is returned in an array. Arrays index from zero where as columns in the spreadsheet begin at 1. Reference
If I misinterpreted your question please ask for further assistance in comments below. I'll be glad to help you.
I am trying to write a script in google sheets that will send one of two different emails based on the response to a multiple choice question. I can get my if/else statement to send either one or the other of the emails but it will not recognize the text of the multiple choice answer and send the correct email.
Here is the full script:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1;
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var title = row[1]; // First column
var startDate = row[3]; // Second column
var endDate = row[4];
var description = row[2];
var location = row[6];
var eventImport = row[5];
var emailAddress = row[7];
var multchoice = row[8];
if (multchoice == "Part Time") {
var subject = "New Hire Part Time Email - " + startDate;
var emailBody = "Congradulations"
var htmlBody = "Congradulations! Part time person"
MailApp.sendEmail (emailAddress, subject, emailBody);
} else {
var subject = "New Hire Appointment - " + startDate;
var emailBody = "Congratulations! We are excited"
var htmlBody = "Congratulation! </i><br/> <br/> We are excited"
MailApp.sendEmail(emailAddress, subject, emailBody);
}
}
}
I believe the problem is here:
if (multchoice == "Part Time")
Any help is greatly appreciated! I am a novice
It looks like you are assigning your variables starting with '1' I stead of '0'. Start assigning them with 0 and counting up.
Without an example sheet to use, I won't be able to do a whole lot of debugging for you.
However, Apps Script comes with it's own debugger. Select the function you wish you debug and click the Little bug icon beside the play button.
Click on the sidebar where you want to set a breakpoint, where the code will stop executing.
Once it hits that breakpoint you can see all the variables currently within your scope. So the array, value, and i variables are visible to you.
Use this to your advantage and debug your code to find out where the issue is. Alternatively, you can use Logger.log() to log values at certain points within your code and then read back through the logs to try and determine where the problem lies.
The problem is not with your if/else statement. The problem is with how you are assigning your variables from your row[] array. While you use regular numbers in the getRange() function, the range that is returned is an array of those cells. Arrays always start with an index of [0]. Change var multchoice = row[8] to var multchoice = row[7] and your if/else statement will work (you'll want to change all of your other references, too).
If I copy/paste the information into both cells my script runs correctly and matches the strings in the cells to the correct row for the user so I can lookup their email. If I let my google form fill the first cell however the data in the two cells no longer matches. I'm probably overlooking something obvious about comparing the strings but hopefully someone can point me in the right direction. Here is the code I have so far.
var rows = SpreadsheetApp.getActiveSheet().getLastRow();
var cell = SpreadsheetApp.getActiveSheet().getRange(rows, 2);
var value = cell.getValue().toString();
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheets()[1]);
var sheet;
var teacher;
var cc = "no match";
for(var h=1; h <= ss.getLastRow(); h++)
{
sheet = ss.getActiveSheet().getRange(h, 2);
teacher = sheet.getValue().toString();
if (value == teacher)
cc = ss.getActiveSheet().getRange(h, 1).getValue().toString();
}
Try to use watchdog (clicking on line number) or some message box to see what happens
i.e. Browser.msgBox(teacher); bebore testing the value of value ^^
and may be don t use the "value" as a variable name, it could generate problem to execute the script.
I am trying to parse a CSV file I made in Excel. I want to use it to update my Google map. This Google map is in a mobile app that I am developing with Eclipse for Android.
Honestly, I am not sure how to write the JavaScript. Any help will be greatly appreciated. I would be happy to credit your work.
I just want some JavaScript to run when the user hits a button that does the following:
Locates users current location (I have already done this part!)
Locate nearby locations as entered in the .CSV excel file by parsing the .CSV
Display a small link inside every locations notification bubble that says "Navigate" that when the user clicks it, opens google maps app and starts navigating the user to that location from the users current location (Geolocation).
This is the ONLY part I need to finish this application. So once again, any help at all will be greatly appreciated. Thanks everyone!
Honestly, I've been round and round with this problem. The CSV format is not made for easy parsing and even with complicated RegEx it is difficult to parse.
Honestly, the best thing to do is import it into an FormSite or PHPMyAdmin, then re-export the document with a custom separator that is easier to parse than ",". I often use "%%" as the field delimiter and everything works like a charm.
Dont know if this will help but see http://www.randomactsofsentience.com/2012/04/csv-handling-in-javascript.html if it helps...
Additional:
On top of the solution linked to above (my preference) I also used a shed load of stacked regular expressions to token a CSV but it's not as easy to modify for custom error states...
Looks heavy but still only takes milliseconds:
function csvSplit(csv){
csv = csv.replace(/\r\n/g,'\n')
var rows = csv.split("\n");
for (var i=0; i<rows.length; i++){
var row = rows[i];
rows[i] = new Array();
row = row.replace(/&/g, "&");
row = row.replace(/\\\\/g, "\");
row = row.replace(/\\"/g, """);
row = row.replace(/\\'/g, "'");
row = row.replace(/\\,/g, ",");
row = row.replace(/#/g, "#");
row = row.replace(/\?/g, "?");
row = row.replace(/"([^"]*)"/g, "#$1\?");
while (row.match(/#([^\?]*),([^\?]*)\?/)){
row = row.replace(/#([^\?]*),([^\?]*)\?/g, "#$1,$2?");
}
row = row.replace(/[\?#]/g, "");
row = row.replace(/\'([^\']*)\'/g, "#$1\?");
while (row.match(/#([^\?]*),([^\?]*)\?/)){
row = row.replace(/#([^\?]*),([^\?]*)\?/g, "#$1,$2?");
}
row = row.replace(/[\?#]/g, "");
row = row.split(",")
for (var j=0; j<row.length; j++){
col = row[j];
col = col.replace(/?/g, "\?");
col = col.replace(/#/g, "#");
col = col.replace(/,/g, ",");
col = col.replace(/'/g, '\'');
col = col.replace(/"/g, '\"');
col = col.replace(/\/g, '\\');
col = col.replace(/&/g, "&");
row[j]=col;
}
rows[i] = row;
}
return rows;
}
I had this problem which is why I had to come up with this answer, I found on npm a something called masala parser which is indeed a parser combinator. However it didn't run on browsers yet, which is why I am using this fork, the code remains unchanged. Please read it's documentation to understand the Parser-side of the code.
import ('https://cdn.statically.io/gh/kreijstal-contributions/masala-parser/Kreijstal-patch-1/src/lib/index.js').then(({
C,
N,
F,
Streams
}) => {
var CSV = (delimeter, eol) => {
//parses anything beween a string converts "" into "
var innerstring = F.try(C.string('""').returns("\"")).or(C.notChar("\"")).rep().map(a => a.value.join(''));
//allow a string or any token except line delimeter or tabulator delimeter
var attempth = F.try(C.char('"').drop().then(innerstring).then(C.char('"').drop())).or(C.charNotIn(eol[0] + delimeter))
//this is merely just a CSV header entry or the last value of a CSV line (newlines not allowed)
var wordh = attempth.optrep().map(a => (a.value.join('')));
//This parses the whole header
var header = wordh.then(C.char(delimeter).drop().then(wordh).optrep()).map(x => {
x.header = x.value;
return x
})
//allow a string or any token except a tabulator delimeter, the reason why we allow newlines is because we already know how many columns there is, so if there is a newline, it is part of the value.
var attempt = F.try(C.char('"').drop().then(innerstring.opt().map(a=>(a.value.__MASALA_EMPTY__?{value:""}:a))).then(C.char('"').drop())).or(C.notChar(delimeter))
//this is merely just a CSV entry
var word = attempt.optrep().map(a => (a.value[0]?.value??a.value[0]));
//This parses a CSV "line" it will skip newlines if they're enclosed with doublequotation marks
var line = i => C.string(eol).drop().then(word.then(C.char(delimeter).drop().then(word).occurrence(i - 1).then(C.char(delimeter).drop().then(wordh)))).map(a => a.value);
return header.flatMap(a => line(a.header.length - 1).rep().map(b => {
b.header = a.header;
return b
}))
};
var m = {
'tab': '\t',
"comma": ",",
"space": " ",
"semicolon": ";"
}
document.getElementById('button').addEventListener('click', function() {
var val = document.getElementById('csv').value;
var parsedCSV = CSV(m[document.getElementById('delimeter').value], '\n').parse(Streams.ofString(val)).value;
console.log(parsedCSV);
})
})
Type some csv<br>
<textarea id="csv"></textarea>
<label for="delimeter">Choose a delimeter:</label>
<select name="delimeter" id="delimeter">
<option value="comma">,</option>
<option value="tab">\t</option>
<option value="space"> </option>
<option value="semicolon">;</option>
</select>
<button id="button">parse</button>
I would suggest stripping the newlines and the end of the file. Because it might get confused.
This appears to work. You may want to translate the Japanese, but it is very straight-forward to use:
http://code.google.com/p/csvdatajs/