Google App Script: Trying to setFormula for Spreadsheet cell - google-apps-script

I am trying to set the formula for a Google Spreadsheet cell using the cell.setFormula function.
This is my code from the function. The line of code of importance is the last one where I try to setFormula.
//Create new empty project sheet
function copySheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var temp = ss.getSheetByName("Project_Template");
var name = Browser.inputBox("Create New Project", "Enter name for new project", Browser.Buttons.OK_CANCEL);
if (name != "cancel") {
ss.insertSheet(name,1, {template:temp})
//Add project name to project code cell
var newSheet = ss.getSheetByName(name);
var cell = newSheet.getRange(3, 2);
cell.setValue(name);
//Update formula in placemarkers sheet
var rowNum = ss.getNumSheets() - 3;
var formulaSheet = ss.getSheetByName("Placemarkers");
var formulaCell = formulaSheet.getRange(rowNum, 1);
formulaCell.setFormula('=if(isna(filter('name'!AH3:AH3,'name'!AH3:AH3 <> ""))=true,"",filter('name'!AH3:AH3,'name'!AH3:AH3 <> ""))');
}
}
When I try to save the script, I get the following error message:
Missing ) after argument list. (line 103)
I am sure it has to do with the combination of quotation and double quotation marks. I have not been able to get it working without an error message. Any help would be appreciated.

The + operator is not inserted to join string and the name variable. The following code part fixes the problem
formulaCell.setFormula('=if(isna(filter(' + name + '!AH3:AH3,' + name + '!AH3:AH3 <> ""))=true,"",filter(' + name + '!AH3:AH3,' + name + '!AH3:AH3 <> ""))');

.. it is not working to me.
cell.setFormula("=COUNTIF('name'!B14:B71,"G:*")");
cell.setFormula("=COUNTIF(' + name + '!B14:B71,"G:*")");
I guess that problem is with " in the setFormula's input.
It takes the " in the content of formula as a terminator of its parameter field and awaits ) symbol to enclose method call.
Solution:
Insert \ before " in the setFormula string:
cell.setFormula("=COUNTIF('name'!B14:B71,\"G:*\")");
_

Related

how to combine web adress with string value in hyperlink google sheets

could someone help with how to properly combine string value from variable with text chain to create the desired hyperlink?
I am getting error message probably because the ' ' and ""are not used the right way.
I also dunno if the + sign or the & should be used.
var sheet = sss22.getSheetByName('Otevrene zakazky');
var cislo = sheet.getRange(1, 1).getValue().toString();
var refSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(cislo);
var refSheetId = refSheet.getSheetId().toString(); //string value (ID number of the sheet)
var source987 = sht.getRange(sht.getLastRow(), 1)
var source2222 = source987.setValue('=hyperlink("https://docs.google.com/spreadsheets/d/2M_Q1q2ElA29bRmwp2-MKQDciv2W3zs/edit#gid=' + refSheetId"), "Detail Zakázky")');
Thank you in advance,
Matt
You forgot the second + and opening '. You also don't need the closing parenthesis that you wrote here refSheetId").
This should be your final line:
var source2222 = source987.setValue('=hyperlink("https://docs.google.com/spreadsheets/d/2M_Q1q2ElA29bRmwp2-MKQDciv2W3zs/edit#gid=' + refSheetId + '", "Detail Zakázky")');

How to delete a page from a google doc using app script

I have created a template with several pages. After the template is used, I want to automatically remove any unused page.
This is how it works. I have created a certificate template with 25 pages with placeholders for name and other details. Each page is a certificate. After going through the data, the code below replaces the placeholders with data from the Google Sheets. Once that is completed - I want to remove all the extra pages in the document - for example: if only 5 template pages are modified, I want to remove the remaining 20 template pages from the document.
Any other improvement suggestions are welcome as this is my first App Script.
Addition to clarify the question:
The script takes data from a Google Sheet which has hundreds of rows of data. For example, if 5 certificates need to be created, the script gets all the data and loop and look for a certain flag (cert_data[i][6] == 1) to identify the rows of data that should be used for the certificate. Once the flag is found, the data in the row are stored in variables and is used to replace the place holders in the template file. Once the data in all flagged rows are replaced - for this example, only 5 template pages are replaced. Hence there will be a balance of 20 pages in the template that has not been used - I want to delete these pages.
function createDocument() {
//Setting ID for database
var SPREADSHEET_ID = "doc ID"
var spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
var worksheet = spreadsheet.getSheetByName("Sheet1");
var cert_data = worksheet.getDataRange().getValues();
//Setting template ID
var templateId = 'template ID goes here';
//Make a copy of the template file
var documentId = DriveApp.getFileById(templateId).makeCopy().getId();
//Get the document body as a variable
var body = DocumentApp.openById(documentId).getBody();
//Foramt date
var curDate = Utilities.formatDate(new Date(), "GMT+1", "dd MMMM yyyy")
var d = 0;
//Looping through all the data that is in the Google Sheet
for(var i = 1; i < cert_data.length ; i++){
var curdata = cert_data[i][6];
//Checking if the row data is to be used to create certificate
if (cert_data[i][6] == 1) {
var training_type = cert_data[i][12];
var hours = cert_data[i][9];
var user_name = cert_data[i][1];
var NIC = cert_data[i][3];
var date_completed = Utilities.formatDate(cert_data[i][8], "GMT+1", "dd MMMM yyyy");
var company = cert_data[i][2];
var cert_number = cert_data[i][0];
var date_now = curDate;
//Setting training names
if (training_type == "01G") {training_type = "Basic First Aid" + String.fromCharCode(10) + "& Automated External" + String.fromCharCode(10) + "Defibrillator Certificate"; var file_name = 'AED Training';}
if (training_type == "01B") {var file_name = 'Refresher Receipts';}
d++;
//Insert the data into the file
body.replaceText('{training_type' + d + '}', training_type);
body.replaceText('{hours' + d + '}', hours);
body.replaceText('{name' + d + '}', user_name);
body.replaceText('{NIC' + d + '}', NIC);
body.replaceText('{date_completed' + d + '}', date_completed);
body.replaceText('{company' + d + '}', company);
body.replaceText('{cert_numb' + d + '}', cert_number);
body.replaceText('{date_now' + d + '}', date_now);
}
}
//d is the number of pages used from the template file
//I want to delete all the balance pages (i.e. 25-d = x)
//Rename the copied file
DriveApp.getFileById(documentId).setName(file_name + ' - ' + company);
}
Each page of your Google Document is separated by the page breaks.
You want to delete several pages of Google Document from the last page in order.
Number of pages you want to delete is decided by your script.
If my understanding is correct, how about this sample script? The flow of this script is as follows.
Flow:
Retrieve paragraphs in the body of Document.
Retrieve elements in each paragraph. The page break is included in the paragraph.
Delete elements from last page in order.
When the number of page breaks is the same with deletePages, the script is stopped.
By this flow, several pages can be deleted from the last page in order.
Sample script:
Please copy&paste the following script and set the variables of deletePages and id. Then, run the script.
function myFunction() {
var deletePages = 3;
var id = "### documentId ###";
var paragraph = DocumentApp.openById(id)
.getBody()
.getParagraphs();
var counter = 0;
for (var i = paragraph.length - 1; i >= 0; i--) {
for (var j = 0; j < paragraph[i].getNumChildren(); j++)
if (
paragraph[i].getChild(j).getType() == DocumentApp.ElementType.PAGE_BREAK
)
counter++;
if (counter < deletePages)
paragraph[i].clear();
else if (counter == deletePages){
paragraph[i].getChild(paragraph[i].getNumChildren() - 1).removeFromParent();
break;
}
}
}
Note:
If you want to delete 5 pages from the last page, please set var deletePages = 5.
Also you can use this function like myFunction(deletePages) as a method. At that time, please remove var deletePages = 3;.
You can also use DocumentApp.getActiveDocument() instead of DocumentApp.openById(id).
From #derekantrican's suggestion, I updated the sample script.
References:
getParagraphs()
getChild()
clear()

How to consider empty answers in Google form using Google Apps Script?

I made a Google form and a script that sends a mail with the content of the form.
There are 3 fields: A, B, C that are not mandatory.
Example: If we enter 1, 5, and 8 then the script is writing:
A=1, B=5, C=8
The problem is that if B is not given a value (1 for A and 3 for C), then I get the output:
A=1, B=3, C=
There is a shift of the values!
What can I do ?
function sendResponses() {
var form = FormApp.getActiveForm();
var responses = form.getResponses();
var lastrow = responses.length - 1;
var itemResponses = responses[lastrow].getItemResponses();
var Total = "A=" + itemResponses[0].getResponse() + ", B=" + itemResponses[1].getResponse() + ", C=" + itemResponses[2].getResponse(),
}
Thank you,
Frédéric
When I use this code, it's giving me the results that you want:
function sendResponses(e) {
var thisResponse = e.response;
Logger.log('thisResponse: ' + thisResponse);
var itemResponses = thisResponse.getItemResponses();
Logger.log('itemResponses: ' + itemResponses);
var Total = "A=" + itemResponses[0].getResponse() + ", B=" + itemResponses[1].getResponse() + ", C=" + itemResponses[2].getResponse();
Logger.log('Total: ' + Total);
}
Note that you don't need to get all the form responses. Your code retrieves all responses, past and present. You can get just the current response. Note the variable e as an argument in the sendResponses function:
function sendResponses(e) {
I created a form with three text fields, and did not put anything in the second field. The Log prints this:
[14-09-10 16:25:44:265 EDT] thisResponse: FormResponse
[14-09-10 16:25:44:267 EDT] itemResponses:
ItemResponse,ItemResponse,ItemResponse
[14-09-10 16:25:44:268 EDT] Total: A=1, B=, C=C
The function is triggered when the form is submitted:
Get the responses using named values instead of indexes... there won't be any possible confusion.
See documentation here.
You can retrieve the item names with the FormApp method getTitle()
Example :
e.namedValues {'First Name': ['Jane'], 'Timestamp': ['6/7/2015 20:54:13'], 'Last Name': ['Doe']} An object containing the question names and values from the form submission
See this other post for a full example.

Google Script for Spreadsheets - error: Argument must be a range

I am new to google scripting and am running into something I can't figure out. I am trying to name a range with the hope of eventually putting it into an array and populating another sheet with the data.
I am running into problems naming the range. I want to eventually be able to iterate through and name many ranges, so I'd like to be able to use variables for the row numbers.
If I try this:
var rngProject = "A8:Y21";
var RngName = "project1";
Then everything works and I have the data in an array. But, as mentioned, I want to use variables for the row numbers, as well as the range name, as shown below.
If I try this:
var rngProject = "A" + strtRow + ":Y" + totRows + strtRow - 1;
var RngName = "project" + toString(i);
On this line:
var rng_to_name = active_spreadsheet.getSheetByName(sheet_name).getRange(address);
I am getting the error: "Argument must be a range." In the debugger the address value shows as NaN, so I think this is not right. But I've also tried using strRange (commented out below) and I get the same error on the same line.
Is there a way I can take this value and cast it to a range type, or is there something else I am doing wrong?
function namePrjRange () {
var i = 1
var strtRow = 8;
var shtName = "USER INPUT by week: TEST";
var totRows = 14;
//var strRange = "A" + toString(strtRow) + ":Y" + toString(totRows + strtRow - 1);
var rngProject = "A" + strtRow + ":Y" + totRows + strtRow - 1;
var RngName = "project" + toString(i);
//Logger.log(strRange);
Logger.log(rngProject);
Logger.log(RngName);
nameRange(shtName, rngProject, RngName);
}
// Given a sheet name (assumed to be in the active spreadsheet, an address using "A1" notation,
// and a name string, assign that name to the range address in the given sheet.
function nameRange(sheet_name, address, rng_name) {
// Create an spreadsheet object.
Logger.log("Entered nameRange function")
var active_spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// Get a range object by firstly getting a sheet object from the spreadsheet object and then pass the
// "address" argument to the sheet "getRange()" method.
var rng_to_name = active_spreadsheet.getSheetByName(sheet_name).getRange(address);
// Use the spreadsheet object method "setNamedRange()" to assign a range name to a range object.
Logger.log("About to set Named Range");
Logger.log(rng_name);
Logger.log(rng_to_name);
active_spreadsheet.setNamedRange(rng_name, rng_to_name);
}
Use:
var rngProject = "A" + strtRow + ":Y" + (totRows + strtRow - 1);
As you are performing string concatenation here, the parser would be attempting to concatenate everything together (ie not actually adding totRows to strtRow), and ultimately drop it's bundle when it arrives at the minus sign, which isn't a valid string operator. So you just need to put parentheses around the arithmetic part.
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Expressions_and_Operators#String_operators

Setting Script Property using it in "if" in Google

I have a script that is supposed to mail a chart URL when a metric falls out of X range and Only if someone has entered a new metric. It's mailing everytime I run the script so I know the setProperty is not working and the "if" statement isn't working because it's only supposed to mail if X is TRUE.
The sheet... https://docs.google.com/spreadsheet/ccc?key=0Ai_2YLvaQba0dHN1dWFpY0ZSbGpudWF4cTJYNlFwNHc&usp=sharing
My code...
function myAverages() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var value = ss.getSheetByName("EmailServices").getRange("P2").getValue().toString();
var outside = ss.getSheetByName("EmailServices").getRange("S2").getValue().toString;
var mailed = ss.getSheetByName("EmailServices").getRange("T2").getValue().toString();
var stemiAverage = ss.getSheetByName("EmailServices").getRange("R2").getValue().toString();
var stemiChart = ss.getSheetByName("EmailServices").getRange("U2").getValue().toString();
var last = ScriptProperties.getProperty('last');
//if "value" is not equal to ScriptProperty "last" AND "outside" is TRUE, then mail
if(value =! last, outside = "TRUE")
{
MailApp.sendEmail("dave#mydomain.com", "Metric Warning",
"Yearly STEMI Average has fallen below 65%, it is now: " + stemiAverage + "%" +
"\n\nTo see the current trending chart " + stemiChart + "\n\n The sheet that calculated this is here " + ss.getUrl());
ScriptProperties.setProperty('last','value');
}
}
Thanks for any help you can lend. I'm teaching myself this stuff and feel very much like a newby. I've tried a hundred or more combinations to the script before posting here.
As a complement to Phil's answer and following your comment, there is another error in your script :
ScriptProperties.setProperty("last","value");
should be
ScriptProperties.setProperty({'last':value},true);
The true parameter is optional, see documentation on ScriptProperties, it gives you the possibility to delete all other keys.
So you're complete function with corrections would be :
function myAverages(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var value = ss.getSheetByName("EmailServices").getRange("P2").getValue().toString();
Logger.log('value = '+value)
var outside = ss.getSheetByName("EmailServices").getRange("S2").getValue().toString();
Logger.log('outside='+outside)
var mailed = ss.getSheetByName("EmailServices").getRange("T2").getValue().toString();
Logger.log('mailed = '+mailed)
var stemiAverage = ss.getSheetByName("EmailServices").getRange("R2").getValue().toString();
var stemiChart = ss.getSheetByName("EmailServices").getRange("U2").getValue().toString();
var last = ScriptProperties.getProperty('last');
Logger.log('last='+last)
if(value != last && outside == "true"){
MailApp.sendEmail("me#mydomain.com", "Metric Warning",
"Yearly STEMI Average has fallen below 65%, it is now: " + stemiAverage + "%" +
"\n\nTo see the current trending chart " + stemiChart + "\n\n The sheet that calculated this is here " + ss.getUrl());
ScriptProperties.setProperty({'last':value});
Logger.log('mail sent')
}
}
You need to use the AND operator: &&.
And also, checking for equality requires 2 equals signs: ==.
So be sure you try this:
if (value!=last && outside=="TRUE") {