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

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

Related

TypeError when cell contains double figures

The code below is working how I want it too except when cell A1 is large then 9. As soon as I enter anything greater like 10 or 11, I get the error
"TypeError: theSplitString.split is not a function"
What am I doing wrong?
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssSheet = ss.getSheetByName('Quote List');
var copyViewQuote = ss.getSheetByName('New Job');
var quoteNuber = copyViewQuote.getRange("A1").getValue();
Logger.log(+quoteNuber)
var theSplitString = ssSheet.getRange("M" + quoteNuber).getValue(); // WHICH PARTS STRING TO USE
var thePartAmount = ssSheet.getRange("N" + quoteNuber).getValue(); // GIVES YOU THE NUMBER OF PARTS IN THE STRING
var spiltstring = theSplitString.split(","); // WHAT SPILTS THE PARTS IN THE STRING
var data = 1; // START FROM 1 AS 0 GIVES UNDEFINED AS FIRST PART OF STRING
var partListNumer = 1;
copyViewQuote.getRange('H5:L200').clearContent();
for(row=5; row<=5+thePartAmount; row++){
//if (partListNumer <= thePartAmount){
//copyViewQuote.getRange(row, 8).setValue(partListNumer);
//partListNumer = partListNumer + 1
//}
//each spiltstring array data is put on Column 6 or column F that starts from row 10 to 10 + length of the splitstring array
copyViewQuote.getRange(row,9).setValue(spiltstring[data]);
data++;
copyViewQuote.getRange(row,10).setValue(spiltstring[data]);
data++;
copyViewQuote.getRange(row,11).setValue(spiltstring[data]);
data++;
copyViewQuote.getRange(row,12).setValue(spiltstring[data]);
data++;
}
}
Looks like you're trying to split the value of the cell, which can only be done on strings.
Try this on your sheet:
This will force all call data to be strings, which you can work a split function on. That should fix the issue.

"TypeError: Cannot read property 'substring' of undefined" while using two substrings in two different functions

I have images which are stored as file paths in a spreadsheet. The image is extracted via Google Apps Script by creating a substring of their file path name and using it to find the image in a pre specified folder. I to extract 3 signatures per data set, but I am only able to extract one.
function motorElectInstallSignature(row, body){
var signature = row[22];
var sign = signature.substring(signature.indexOf("/") + 1);
var sigFolder = DriveApp.getFolderById("16C0DR-R5rJ4f5_2T1f-ZZIxoXQPKvh5C");
var files = sigFolder.getFilesByName(sign);
var n = 0;
var file;
while(files.hasNext()){
file = files.next();
n++;
} if(n>1){
SpreadsheetApp.getUi().alers('there is more than one file with this name' + sign);
}
var sigElectInstaller = "%SIGNELECTINSTALL%";
var targetRange = body.findText(sigElectInstaller); // Finding the range we need to focus on
var paragraph = targetRange.getElement().getParent().asParagraph(); // Getting the Paragraph of the target
paragraph.insertInlineImage(1, file.getBlob());// As there are only one element in this case you want to insert at index 1 so it will appear after the text // Notice the .getBlob()
paragraph.replaceText(sigElectInstaller, ""); // Remove the placeholder
}
This function works as intended with no errors.
This next function is where the error occurs.
function motorCommEngineerSig(row, body){
var signature1 = row[69];
var signCommEng = signature1.substring(signature1.indexOf("/") + 1);
var sigFolder = DriveApp.getFolderById("16C0DR-R5rJ4f5_2T1f-ZZIxoXQPKvh5C");
var files = sigFolder.getFilesByName(signCommEng);
var n = 0;
var file;
while(files.hasNext()){
file = files.next();
n++;
} if(n>1){
SpreadsheetApp.getUi().alers('there is more than one file with this name' + signCommEng);
}
var sigCommEng = "%SFCE%";
var targetRange = body.findText(sigCommEng); // Finding the range we need to focus on
var paragraph = targetRange.getElement().getParent().asParagraph(); // Getting the Paragraph of the target
paragraph.insertInlineImage(1, file.getBlob());// As there are only one element in this case you want to insert at index 1 so it will appear after the text // Notice the .getBlob()
paragraph.replaceText(sigCommEng, ""); // Remove the placeholder
}
The error occurs on this line:var signCommEng = signature1.substring(signature1.indexOf("/") + 1);
As you can see, there is no difference between both functions, with the exception of some variable names and a row number. These functions work as intended multiple times in a script that I have previously written. These functions serve the same purpose here as they did in my previous script and they are written the exact same way.
The speradsheet can be found here
The Script can be found here
I think your issue is with how you're defining signature1 in motorCommEngineerSig():
var signature1 = row[69];
row[69] refers to the 70th (0-index) column in your data. However, where you've previously defined row, you only provided 47 columns of data:
var data = sheet.getRange(2, 2, 10, 47).getValues();
.
.
.
var row = data[rowNumber];
In motorElectInstallSignature(), you defined the signature in column 22, which is in range of the data and why it worked for that function.
From MDN JavaScript reference:
A TypeError may be thrown when an operand or argument passed to a function is incompatible with the type expected by that operator or function, or when attempting to modify a value that cannot be changed, or when attempting to use a value in an inappropriate way.
That happens essentially because the element you get from row, in your case row[69] does not have a substring method. That could be because:
The element exists in the row, but is not of the string type. The element could instead be a Number, Object, etc.
The element is not present in the list (the list does not hold that many items). In this case, the row[69] expression returns undefined, which does not posses that method thus returning an error when invoked.
Based on your particular error message, the second option seems to be the one occurring.
In order to fix your issue I recommend you use the built-in debugging tools such as console.log or Logger.log.
Furthermore, I would also recommend you check out the following link: Apps Script troubleshooting.

Fill multiple rows in google spreadsheet via google script

I am currently working on a semester project for my university in which we want to log data from an Arduino to a Google Sheet.
I was following the numerous tutorials and examples that I could find on Google and it worked so far really, really well. My Arduino is able to upload data to said spreadsheet.
Unfortunately all those examples always only deal with one row to be filled. For our project we would like to fill 2 or 3 lines simultaneously.
I will shortly show what I have done so far and maybe you can help me solve my (probably easy) problem.
I created a google spreadsheet in which I want to log my data
I used the script from a tutorial that should fill one row.
By typing the following line in my browserhttps://script.google.com/macros/s/<gscript id>/exec?tempData=datahereI am now able to fill row one with my data in enter in the end of the url.
But how do I progress now, when I want to fill two or three rows of the table? I say that the author of the code already implemented an option to fill the third row, yet I can't find out what to input in my url then to fill it with data.
All my attempts to write something like
https://script.google.com/macros/s/<gscript id>/exec?tempData=datahere&tempData1=value2
just ended in writing
datahere&tempData1=value2
in my first row, not filling datahere into the first and value2 in to the second row.
How can I provide and write multiple rows of data?
The code in this script is:
/*
GET request query:
https://script.google.com/macros/s/<gscript id>/exec?tempData=data_here
*/
/* Using spreadsheet API */
function doGet(e) {
Logger.log( JSON.stringify(e) ); // view parameters
var result = 'Ok'; // assume success
if (e.parameter == undefined) {
result = 'No Parameters';
}
else {
var id = '<ssheet id>'; // Spreadsheet ID
var sheet = SpreadsheetApp.openById(id).getActiveSheet();
var newRow = sheet.getLastRow() + 1;
var rowData = [];
//var waktu = new Date();
rowData[0] = new Date(); // Timestamp in column A
for (var param in e.parameter) {
Logger.log('In for loop, param='+param);
var value = stripQuotes(e.parameter[param]);
//Logger.log(param + ':' + e.parameter[param]);
switch (param) {
case 'tempData': //Parameter
rowData[1] = value; //Value in column B
break;
case 'tempData1':
rowData[2] = value; //Value in column C
break;
default:
result = "unsupported parameter";
}
}
Logger.log(JSON.stringify(rowData));
// Write new row below
var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
newRange.setValues([rowData]);
}
// Return result of operation
return ContentService.createTextOutput(result);
}
/**
* Remove leading and trailing single or double quotes
*/
function stripQuotes( value ) {
return value.replace(/^["']|['"]$/g, "");
}
I would suggest the following:
Create a 2d array of your data you wish to write to the spreadsheet. If your client on Arduino were using JavaScript this might look like :
var data = [
["row1value1", "row1value2"],
["row2value1", "row2value2"]
];
Convert this to JSON, again in JavaScript this might look like:
var json = JSON.stringify(data);
This gives you a string representation of your array.
Now make your request using this data. I would suggest you should look at using doPost instead of doGet, as you are sending data to the spreadsheet that updates state. However, for the purposes of getting something working, your URL would look like:
https://script.google.com/<.....>/exec?myarray=<stringified JSON>
In Apps Script, in your doGet (again, consider using doPost instead), you could then use:
// Get the JSON representation of the array:
var json = e.parameter.myarray;
// Convert back to 2d array
var data = JSON.parse(json);
Now you can write this to a Range in Sheets using setValues, e.g. assuming a rectangular 2d array:
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
Hope this helps

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 App Script: Trying to setFormula for Spreadsheet cell

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:*\")");
_