Issue with .replace function - javascript

So I have a Google sheet that collects registration data from customers. Included in the data collected is a student's name, the session the student elected to attend and a credit card number. Once a submission has been made, I get a notification. Upon notification, I go to my Google sheet and charge the credit card the appropriate amount.
Once the credit card has been charged, I then want to generate a confirmation email to the customer, which is based on a text template in cell A1, i.e., (1,1) on sheet2, that includes the student's name (Range C2), the session the student registered to attend (range D2) and the amount charged to the credit card (Range E2). Simply put, I want to replace curly bracket placeholders in my "template text" (i.e., {Name},{sessions} and {Cost} with the actual values which I've defined as variables.
For the life of me, I cannot get this to work.
Here's the error detail I get when I try to run this code:
Type Error: Cannot find function replace in object This is the email body. This is the amount charged to the credit card: {Cost}.
I've been all over the web on this. I've watched YouTube videos. I've read what seems like mountains of online documentation, none of which has provided any meaningful help. I've frustrated myself trying to figure out how the logger works and still, it's a complete mystery to me. Very frustrated!
Also, is there a way I can share my project with the forum community so someone out there can actually look at my code in action??? I wish there was a site for Apps Script that works like the ExcelForum does for questions about VBA programming.
function SendEmail2() {
// fetch these values as you need
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("B2").getValues();
var studentRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("C2").getValues();
var sessionRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("D2").getValues();
var chargeAmt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("E2").getValues();
var studentName = studentRange;
var sessionName = sessionRange;
var emailAddress = emailRange;
var charge = chargeAmt;
var templateText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1,1).getValues();
// This is what needed to change
var emailText = templateText
.replace("{Name}", studentName)
.replace("{Sessions}", sessionName)
.replace("{Cost}", charge);
var subject = 'Junior Golf Clinic Registration Receipt';
var message = emailText;
MailApp.sendEmail(emailAddress, subject, message);
}
This is the email body.
This is the amount charged to credit card {Cost} // should be replaced with the value of the var "charge".
This is the student's name: {Name}. //Should be replaced with the value associated to the var "studentName"]
These are the sessions the student is scheduled to attend: {Sessions} //Should be the value associated with the var "sessionName".

At the moment your script is trying to do replace on whatever values it gets, but the values are not treated as a string, therefore .replace will not work as you're expecting.
Try using .toString() like below, I've also cleaned up some of the other variables in your script as there's no real reason to define then rename them.
function SendEmail2() {
//spreadsheet variables
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = spreadsheet.getSheetByName("Sheet1");
//fetch values from spreadsheet
var emailAddress = dataSheet.getRange("B2").getValues();
var studentName = dataSheet.getRange("C2").getValues();
var sessionName = dataSheet.getRange("D2").getValues();
var charge = dataSheet.getRange("E2").getValues();
var templateText = spreadsheet.getSheetByName("Template").getRange(1,1).getValues();
//get templateText as string and replace values with variables defined above
var emailText = templateText.toString()
.replace("{Name}", studentName)
.replace("{Sessions}", sessionName)
.replace("{Cost}", charge);
var subject = 'Junior Golf Clinic Registration Receipt';
var message = emailText;
MailApp.sendEmail(emailAddress, subject, message);
}
As you can see I have added .toString() at the start of your replace:
var emailText = templateText.toString()

Related

How to make a dynamic source for .getRange() in Apps Script?

Original Question:
I have multiple tabs in a Google Spreadsheet that represent different data sources. Currently, I have a variable (var = quote1location) that is equal to the sheet name that I would like to get my data from based on other logic.
Pretend that quote1location can equal 'Sheet1', 'Sheet2', or 'Sheet3' depending on the logic but for this case, it equals 'Sheet1'.
var totalpeople = quote1location.getRange('A1').getValue();
In the function above, Apps Script will return an error saying 'quote1location.getRange is not a function' because Apps Script is not substituting the value of the variable that I have designated ('Sheet1') but is using the variable name ('quote1location' instead. I would like Apps Script to process this as 'Sheet1.getRange('A1').getValue()'.
Your help would be appreciated
Answer:
Thank you all for your responses. What I was trying to do is use a string in the 'getRange()' function. Pretend I had two Google Sheets named 'Sheet1' and 'Sheet2' and I had a variable that helped me determine what sheet to grab as my data reference. I was trying to set a variable as either (var source = 1) or (var source = 2) so that I could then use this variable in my getRange() function like this: ('Sheet' + source).getRange('A1').getValue();
What I was trying to do here is if var source = 1, then I would get my data from 'Sheet1'. If the var source = 2, then I would get my data from 'Sheet2'.
The issue (as mentioned by those who responded) is that I was trying to use .getRange() on a string, not an object like a specific spreadsheet. Instead of using var source = 2 or var source = 1 I should be using
ss = SpreadSheetApp.getActiveSpreadsheet()
if(somevariable = somecondition){
var source = ss.getSheetbyName('Sheet1')
}
if(someothervariable = someothercondition){
var source = ss.getSheetByName('Sheet2')
}
Now when I use getRange()' on 'source', it will be calling the sheet that I have designated rather than trying to retrieve a range from a string which will not work.
Thank you very much to all who provided feedback.
I believe you are looking to do:
const quote1Location = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName(`Sheet1`)
const totalPeople = quote1Location.getRange(`A1`).getValue()
Alternatively:
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
const quote1Location = `Sheet1`
const totalPeople = spreadsheet.getSheetByName(quote1Location)
.getRange(`A1`)
.getValue()
Whether these are the exact syntax you're hoping to use or not, I hope this helps you better understand how to accomplish accessing a Sheet.

skipping a filled cell that was input manually by the automated apps script

I'm relatively new to google apps Script coding but I have taken the Javascript learning on Khan and i need some assistance with a problem I'm trying to figure out in google spreadsheets.
The problem is that I am trying to automate information from one sheet to the other like a copy so if an assistance inputs info the manager when he pulls out sheets, it will automatically have the info loaded. I have that part the part I need is if the manager puts in a piece of info I don't want the assistances info to overlap it.
I am pretty sure I need an if statement but not sure how to correctly word it in Apps Script.
This is what I have so far:
function onOpen(e){
/*SpreadsheetApp.getUi()*/
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var ss = sheet.getSheetByName('names');
var range = ss.getRange('B2:B100');
var data = range.getValues();
var sheet1= SpreadsheetApp.getActive();
var ds = sheet1.getSheetByName('Sheet1');
ds.getRange(2,2, data.length, data[0].length).setValues(data);
var sheet2 = SpreadsheetApp.getActiveSpreadsheet();
var sss = sheet2.getSheetByName('names');
var range2 = sss.getRange('C2:C100');
var data2 = range2.getValues();
var sheet3= SpreadsheetApp.getActive();
var ds1 = sheet3.getSheetByName('Sheet1');
ds1.getRange(2,1, data2.length, data2[0].length).setValues(data2);
You can always get the data of the cell then add the updated value so that the data will not overlap.
Sheet 1
A B C
1 Name Work Budget
2 John Guard 180
3 Kevin Prog. 200
Use getValue() of the first sheet, then get the value of the update.Use the variable of the first data and concatenate it with the update to avoid overlapping info.
var range = sheet.getRange("A2");
var data = range.getValue()
range.setValue(data+" Corrs")
Update
Sheet 2
A B C
1 Name Work Budget
2 John Corss Guard 180
3 Kevin Prog. 200
Hope it helps!

Filling cells in range if empty in google spreadsheet form submission

I'm trying to make a script that sends out a custom email confirmation to the user. However, I noticed that if any of the cells are blank the script will not work. I was wondering how to I like highlight the last entry of the table and check the cells, that if the cell is empty then change it's value to 0 or a dash. Here's what I got going:
function Confirmation(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var lastRange = sheet.setActiveRange(sheet.getRange(lastRow,5,1,2));
//lastRange.setValues(1111);
var EmailAdd = e.values[1];
var Name = e.values[2];
var Type = e.values[3];
var Criteria1 = e.values[4];
var Criteria2 = e.values[5];
var Criteria3 = e.values[5];
MailApp.sendEmail(EmailAdd, "Your request has been received" ,
"Thank you, " + Name + " for submitting your request.
)
}
the
lastRange
line already highlights the last entry. How can I evaluate each cell and check if it's empty change it's value and if not move to the next cell.
*I always get an "cannot read property "values" from undefined" is this because it's empty or because I set it as an event triggered function. Sorry I'm new to javascript & google apps script
As indicated in the comment above, Mogsdad's link provides a good work around for this problem. See link: e.values in google forms skips empty answers, is there a workaround?

Why does Google Apps Script throw 'ReferenceError: "bold" is not defined' when using .setBold()?

The context: I need to process/correct many text documents containing multiple particular textual errors, highlight keywords in 'bold' and then output the result. I have a Google spreadsheet with two worksheets: one with two columns of 'wrong wordforms' and 'replacement wordforms' (2d array) that I intend to add to over time and use it as a datastore to 'call from;' the other, a single-column collection of words (1d array) I designate "keywords" to check for and then highlight in the target documents.
Things I've tried that worked: I used a basic array iteration loop from a beginner video (I can't add more links yet, I apologize) and swapped in body.replaceText() for the sendEmail(), successfully, to process the corrections from my "datastore" into my target document, which works nearly perfectly. It ignores text values without the exact same case...but that's a problem for another day.
function fixWords() {
// Document to edit
var td = DocumentApp.openById('docId1');
// Document holding comparison datastore
var ss = SpreadsheetApp.openById('docId2');
// Create data objects
var body = td.getBody();
var sheet = ss.getSheetByName("Word Replacements");
var range = sheet.getDataRange();
var values = range.getValues();
// Create a loop (iterate through the cell data)
for (i=1;i<values.length;i++) {
fault = values[i][0];
solution = values[i][2];
body.replaceText(fault, solution);
}
}
Things I've tried that fail: I then tried just swapping out values for setBold() with the replaceText() code, but the closest I got was the first instance of a keyword from the array would be styled correctly, but no further instances of it...unlike ALL of the instances of an incorrectly spelled word being corrected from the Word Replacements array using the fixWords function.
I found the 'highlightTextTwo' example here at stackoverflow which works very well, but I couldn't figure out how to swap in an external data source or force the included different iteration loop to work in my favor.
I've scanned the GAS reference, watched Google developer videos for snippets that might apply...but clearly I'm missing something that's probably basic to programming. But I honestly don't know why this isn't as easy as the body.replaceText() functionality.
function boldKeywords() { // https://stackoverflow.com/questions/12064972
// Document to edit
var doc = DocumentApp.openById('docId1');
// Access the keyword worksheet, create objects
var ss = SpreadsheetApp.openById('docId2');
var sheet = ss.getSheetByName("Keywords");
var range = sheet.getDataRange();
var values = range.getValues();
var highlightStyle = {};
highlightStyle[DocumentApp.Attribute.BOLD] = 'true';
for (i=1; i<values.length; ++i) {
textLocation = values[i];
if (textLocation != null && textLocation.getStartOffset() != -1) {
textLocation.getElement().setAttributes(textLocation.getStartOffset(),textLocation.getEndOffsetInclusive(), highlightStyle);
}
}
}
This throws out 'TypeError: Cannot find function getStartOffset in object DIV. (line 15, file "boldIt").' I guess this means that by just blindly swapping in this code, it's looking in the wrong object...but I cannot figure out why it works for x.replaceText() and not for x.setAttributes() or x.setBold or .getElement().getText().editAsText()...there just doesn't seem to be a "Learn Google Apps Script example" that deals with something this low on a scale of mundane, uninteresting use cases...enough for me to figure out how to direct it to the right object, and then manipulate the "if statement" parameters to get the behavior I need.
My current brick wall: I spotted this example, again, Text formatting for strings in Google Documents from Google Apps Script, and it seemed promising, even though the DocsList syntax has been deprecated (I'm fairly sure). But now I get "bold is not defined" thrown at me. Bold...is not defined. :: mouth agape ::
function boldKeywords() {
// Access the keyword worksheet, create objects
var ss = SpreadsheetApp.openById('docId1');
var sheet = ss.getSheetByName("Keyterms");
var range = sheet.getDataRange();
var values = range.getValues();
// Open target document for editing
var doc = DocumentApp.openById('docId2');
var body = doc.getBody();
// Loop function: find given keyword value from spreadsheet in target document
// and then bold it (highlight with style 'bold')
for (i=1; i<values.length; ++i) {
keyword = values[i];
target = body.findText(keyword);
body.replaceText(target,keyword);
text = body.editAsText();
text.setBold(text.startOffset, text.endOffsetInclusive, bold);
}
}
I will happily sacrifice my firstborn so that your crops may flourish for the coming year in exchange for some insight.
I use this for my scripts, the setStyleAttribute method.
Documentation : https://developers.google.com/apps-script/ui_supportedStyles
Example :
TexBox.setStyleAttribute("fontWeight", "bold");
The bold parameter is a Boolean data type. You need to use the word true or false.
Replace "bold" with "true".
text.setBold(text.startOffset, text.endOffsetInclusive, true);
Check out the "Type" column in the documentation:
Google Documentation - setBold

Google Spreadsheet Determine lowest number in a row of cells

I'm new to this site for the main purpose that I plan to pursue a career in programming. I've landed my first job at an engineering company who is asking me to set up a system in which they can easily determine the time between a job being filed, and it's completion. We're using spreadsheet docs right now to accomplish certain pieces of this.
I'm looking to create a custom function in Google Docs that will allow me to traverse the array of values in row C and then compare it with a number that the function was called with, compare the number to the number in the array and give me which one is the smaller number. EDIT: The function will be called on another sheet called "parsed data" located in the same project file. It's purpose is to automatically file the order number of a current project (just for the sake of being organized) All the other functions I plan to implement will be based off of this order number being correct.
So far, I've gathered this much (I'm learning this on the fly because I still lack experience, so bear with me.)
{
/**created by Alexander Bickford for use at Double E Company
*sorts through a range of values to determine the lowest next value
*returns lowest determined value of next cell
*/
//List Of To Be Implemented Functions
// sheet.appendRow
function setValue(num)
{
var ss = SpreadsheetApp.getActiveSpreadsheet('parsed data');
var ss = ss.getSheets()[0];
var myRange = ss.getRange("C:C").getValues();
newValues = [];
for(i=1;i<=myRange;i++) //Loop to traverse the C range and find the lowest value.
{
if(num<=range[3][i])
{
}
else
num = range[3][i];
}
return num;
}
}
when I call the function in the spreadsheet, I'm getting an error passed that says:
error: ReferenceError: "SPREADSHEET_ID_GOES_HERE" is not defined. (line 8, file "Code")
Google predefines some functions at the top that look like this:
/**
* Retrieves all the rows in the active spreadsheet that contain data and logs the
* values for each row.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
function readRows() { <---Line 8 in the file
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
Logger.log(row);
}
};
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Read Data",
functionName : "readRows"
}];
sheet.addMenu("Script Center Menu", entries);
};
End Code I don't need */
I assume it has something to do with the earlier lines (I pointed out line 8). Any thoughts?
Below code is working fine for me.
var ss = SpreadsheetApp.getActiveSheet();
var myRange = ss.getRange("C:C").getValues();
newValues = [];
for(i=1;i<=myRange.length;i++)
{
Logger.log(myRange[i]);
}
Looking at your code, it seems like you have a few problems.
You seem to be mixing up "sheets" with "spreadsheet", and your redundant declaration of "ss" as a variable is bound to cause you some problems.
You seem to be passing in arguments to the incorrect methods. I had this same problem when working with the Google App script earlier. It took a lot of poking around Google's Documentation (which you should really take a look at: https://developers.google.com/apps-script/). You seem to be making the same mistake I did, coding by analogy. looking at Google's sample code and trying to replicate is bound to bump you into some trouble.
Some useful advice:
The most confusing thing to wrap your head around is the structure: spreadsheet>>sheet>>range, you have to explicitely deal with the one's on top before moving to the one's on the bottom.
Remove the 'parsed data' argument from getActiveSpreadsheet(), it should be blank. What you want to use is "getSheetByName("parsed data")" and pass that into a sheet variable.
In your for loop, you also need to use the ".length" method, or use the ".getLastRow()" method with a sheet object to find the last row in your sheet.
Your code might look something like this:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("parsed data");
var endRowNumber = sheet1.getLastRow();
//insert rest of code

Categories

Resources