Parse #Error When Adding Formula with Javascript - javascript

I am having a really weird phenomenon happen in Google Sheets, and I've found nothing on this issue in my research. I'm adding a query formula with javascript and getting a #Error on the sheet. After quadruple checking I wasn't messing up the formula string (the first and most obvious thing to cause such an error) and satisfying myself that the formula was correct for syntax, I cut the formula from the formula bar, hit enter to make the cell blank, then pasted the formula I just cut back in, and boom. Correct result, no error. No change to the formula whatsoever.
So is the a bug with the script editor/sheet interaction? Is a bug in Sheets? Am I doing something wrong (can't imagine what)?
I even followed another post's suggestion and replaced the comma argument separator with a semicolon, but no change in behavior. I have pasted the relevant code here, but I have also shared a Google sheet with the link below that demonstrates the issue.
To reproduce, follow these steps:
Go to the sheet via the link below.
Open Script Editor, and run the function "AddFormula"
When the script runs it will add the formula shown below and you will see a #Error (parse error).
Cut the formula from the formula bar on the sheet and press enter, creating the blank cell.
Copy the formula you just cut back into the cell. Here you will see the correct result of the formula displayed instead of the #Error.
For reference, the relevant code is here:
var wbID1 = "1tujKM_cAePTjBVS6q-gzGheSOAVz68vI0yi_LigCvyw";
var wb = SpreadsheetApp.openById(wbID1); //The entire workbook.
var wsT = SpreadsheetApp.openById(wbID1).getSheetByName("TData"); //T=Target Worksheet
function AddFormula() {
wsT.clear();
wsT.getRange(2,1).setValue("AL");
var TargetRange = wsT.getRange(2,1).getValue();
var QueryString = "=QUERY(States!A2:E; \"Select D where B = '" + TargetRange + "'\")";
wsT.getRange(2,3).setFormulaR1C1(QueryString);
}
The constructed formula in question resolves to:
=QUERY(States!A2:E, "Select D where B = 'AL'")
A demo sheet is here that reproduces the issue:
Demo Sheet
It would be great if there was a solution to this issue, but if that is too much to ask, I would love to simply be affirmed that I'm not crazy! Thanks all!

Use Range.setFormula(formula), since your formula uses an A1 notation States!A2:E
If you use Range.setFormulaR1C1(formula), the given formula must be in R1C1 notation.
Example: =SUM(R[-3]C[0]:R[-1]C[0])
Your Code:
function AddFormula() {
wsT.clear();
wsT.getRange(2,1).setValue("AL");
var TargetRange = wsT.getRange(2,1).getValue();
var QueryString = "=QUERY(States!A2:E; \"Select D where B = '" + TargetRange + "'\")";
wsT.getRange(2,3).setFormula(QueryString);
}
Output:

Related

Using .indexOf() to define .getRange()

I am currently trying to use the .indexOf of a .getValues() array value, to define the cell I want a hyperlink copied in (as proof of concept).
Code looks as follows:
var descriptionColumn = headerArray[0].indexOf("Description")
sheet.getRange(sheet.getLastRow() + 1, descriptionColumn + 1).setFormula('=HYPERLINK("www.google.com"; "Test")')
Logger.log(descriptionColumn)
The headerArray is filled as follows:
var headerArray = sheet.getRange(1, 1, 1, lastColumn).getValues();
Now the log is showing me, that the descriptionColumn is being returned as "3.0". The position 3 is correct, yet I am unsure if the ".0" is messing with the next code. Because whenever I replace descriptionColumn in the .setFormula area, my code works. Any idea what I'm doing wrong and how to fix it? I am using .indexOf() in other places to refer to the index of another array without issue. Only here I don't get it to work..
EDIT: Reproducible Example and findings.
Thanks a lot for all your help so far, and sorry for coming back so late!!
I have in the meantime found out, that one of the issues was the "+ 1" after sheet.getLastRow() in
sheet.getRange(sheet.getLastRow() + 1, descriptionColumn + 1).setFormula('=HYPERLINK("www.google.com"; "Test")')
I honestly don't fully understand why this is the case yet, but by positioning this at the very end of my code (so that it is indeed the lastRow when inserted, I was able to fix this (saving it in a separate variable such as with "descriptionColumn" also didn't help..). I understood .getLastRow returns an Integer, so the + 1 operation in theory shouldn't be an issue, right? Happy to learn if I got something wrong.
So finally with below code I was able to insert the hyperlink as planned. Indeed starting with .setValue instead of .setFormula did help me a lot, so thanks!! :)
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var headerArray = sheet.getRange(1, 1, 1, lastColumn).getValues();
var projectRef = "TEST123"
var folderID = DriveApp.getFolderById("SOME FOLDERID").createFolder(projectRef).getId()
var descriptionColumn = parseInt(headerArray[0].indexOf("Description"))
sheet.getRange(sheet.getLastRow(), descriptionColumn + 1).setFormula('=HYPERLINK("https://drive.google.com/drive/folders/' + folderID + '"; "' + projectRef + '")')
yet I am unsure if the ".0" is messing with the next code
No, that's not a problem
Only here I don't get it to work
We can't see your error, or description what goes wrong.
--- Debug Steps: ---
Replace .setFormula with .setValue("Test") to see if you are targeting the right cell (column)
If that works, then the problem is in your formula

Form's App Script does not replace fields in template accurately

I have a simple script to generate a doc and PDF upon form submission. It worked well on simple template (e.g. Only 1 sentence, First name, Last name and Company name).
However, when I use a template that's longer, having many fields, and formatting, the code runs but replace the text randomly.
I have tried to hardcode the fields of forms in ascending order as the doc template. However it still replace the text randomly
Can anybody points out what have I done wrong?
My code:
function myFunction(e) {
var response = e.response;
var timestamp = response.getTimestamp();
var [companyName, country, totalEmployees,totalPctWomenEmployees,numberNationality,name1,position1,emailAdd1,linkedin1,funFact1,name2,position2,emailAdd2,linkedin2,gameStage,gameStory] = response.getItemResponses().map(function(f) {return f.getResponse()});
var file = DriveApp.getFileById('XXXXX');
var folder = DriveApp.getFolderById('XXXXX')
var copy = file.makeCopy(companyName + '_one pager', folder);
var doc = DocumentApp.openById(copy.getId());
var body = doc.getBody();
body.replaceText('{{Company Name}}', companyName);
body.replaceText('{{Name}}', name1);
body.replaceText('{{Position}}', position1);
body.replaceText('{{Email}}', emailAdd1);
body.replaceText('{{Linkedin}}', linkedin1);
body.replaceText('{{Fun Fact}}', funFact1);
body.replaceText('{{Game Stage}}', gameStage);
body.replaceText('{{Game Story}}', gameStory);
doc.saveAndClose();
folder.createFile(doc.getAs("application/pdf"));}
My template -
Result -
Question - Does that mean the array declaration in line 3 was supposed to match the order of my form responses columns?
You can use Regular Expresion:
body.replace(/{{Company Name}}/g, companyName); // /g replace globaly all value like {{Company Name}}
Finally I found what have went wrong after so many trials and errors!
The reason is because I declared the array variables randomly without following the order of the form responses columns.
The issue is with the part -
var [companyName, country, totalEmployees,totalPctWomenEmployees,numberNationality,name1,position1,emailAdd1,linkedin1,funFact1,name2,position2,emailAdd2,linkedin2,gameStage,gameStory] = response.getItemResponses().map(function(f) {return f.getResponse()});
It's actually pulling responses from the spreadsheet, and should be corrected in order. The wrongly mapped values was what causing the replacement of text went haywire. I corrected the order as per form responses and it is all good now.
Learning points:
If you swapped around the variables, what response.getItemResponses().map(function(f) {return f.getResponse()} does is that it will go through the form responses column by column in order, and it will map the content to the wrong variable. As a result, when you replace your text later using body.replaceText('{{Game Stage}}', gameStage), there might be possibility that whatever stored in gameStage might be name1. Hence the replaced text will be wrong. And you will scratch your head until it bleeds without knowing why.
I saw #Tanaike's comment after I found the answer, but totally spot on!

Hard stop if a value in a range of cells is not between 2 numbers

I have a page where my team could enter data into one page and then hit a save button, then it would copy and paste the data into a database file then clear the contents of the original page.
What I'm trying to figure out is how I can hard stop the save if the pasted information is incorrect.
example. they copied the incorrect information from the one program we use and paste it into the spreadsheet. but the customer number is in the wrong cell.
This would skew the information in the database.
So my thoughts were to have a criteria check of some sort. So it would check the data in a specific column of cells and check to see if it were between 10000 and 99999 or check to ensure it has 5 digits. then have a second check for something similar.
It would be better if I can find a way to have a Paste button that could paste the information and have the hard stop within that code. But baby steps...
function Copy() {
var sss = SpreadsheetApp.openById('file name here');
var ss = sss.getSheetByName('InputData');
var range2 = sss.getRange('D8:O1000');
var range = ss.getRange('A8:Q1000');
var data = range.getValues();
var tss = SpreadsheetApp.openById('file name here');
var ts = tss.getSheetByName('OutOfStockData');
ts.getRange(ts.getLastRow()+1, 1, data.length, data[0].length).setValues(data);
range2.clearContent();
}
Any help would be greatly apricated.
Thanks.
EDIT.
I'm unable to use forms as we copy the information from an internal WMS program we use. When we copy the information, it gets copied in a format that is recognized by any spreadsheet. So we would just copy and paste into the spreadsheet and then add any extra information needed to each line in the extra columns. (ie. comment column.)
The checks needed is so I can get accurate information on Stockouts. Sometimes an error can be made when one of my teammates copies information from a different window in WMS. so one check like mentioned before would be customer number which is always in column J. and never more than 99999 or less then 10000. another check could be the Case ID which is always in column D which is never more then 9999999 and less then 1000000. verifying these two columns could prevent the data from being skewed if the wrong information is copied from WMS.
So the Information gets Copied from WMS, Pasted into InputData, then when the added information gets entered I would click the save button and it would take all the data in the inputData sheet and copy it into the outofstockdata sheet where It would be used for other metric data needed.
As far as the Paste button, Some of the guys who would need to use this sheet are not very computer literate. So the goal would be to have them press said Paste button and the information from our WMS program which would be on the clipboard within windows(no different than copying and pasting from an email to a word document). which we have copied earlier be pasted into the Frist sheet where we would comment.
Thanks.
To hard stop an script that met a condition use return. This could be shown with vanilla JavaScript
function myFunction(){
var upperLimit = 10;
var lowerLimit = 5;
var input = prompt('Give me a value');
// This is the condition that will hard stop the script.
var condition = input >= lowerLimit && input <= upperLimit;
if (condition){
return; // This hard stop the script.
} else {
//if the condition is not met, continue
myFunction();
}
}
myFunction();

using a variable within a string with Google Sheets

I am using Google Apps for Sheets. I am trying to use a defined variable within a string. I know the variable (lastRow) is the number I want (that number being "11") as I can see it in the logs. I have tried different ways of combining the letter "C" with the variable, but nothing works! I know it works as it is used in the "copyValuesToRange" method. Am I trying to do something that cannot be done, or is there a way to add the variable to the A1 notation so that the range will be read as C1:C11? Thanks from a relatively novice newbie!
var lastRow = sheet.getLastRow();
Logger.log(sheet.getLastRow());
// Inserts 1 column after column A=1 (Seq)
sheet.insertColumnsAfter(1,1);
// New column(s) due to added column(s)
var range = sheet.getRange("C1:ClastRow");
//Copied to Col A=1
range.copyValuesToRange(sheet,1,1,1,lastRow);
While writing this, the "Similar Question" box showed a link to "Google script string with a variable". I looked at that, but did not understand it "(!
You dont do it like that, you need to know concatenation.
var lastRow = 11;
console.log("C"+lastRow);
will output:
C11
which is what you're going for.
var range = sheet.getRange("C1:C"+lastRow);

How to set formula by using google spreadsheets app script?

Actually, question is - how to recreate type of formulas:
ArrayFormula(replace(replace(regexreplace(K1:K&"","[-/,. ()]",""),4,0,"-"),8,0,"-"))
into code. Unfortunately, i didn't find it by myself, so I'm asking for help.
Upd.
Let me clarify just a little.
Part of code which was used by me into script:
value = value.replace(/^ /, '').replace(/[. )]/g, 'a').replace(/[+]/g, '').replace(/(aa)/g, '-').replace(/(a)/g, '-').replace(/[(]/g, '-');
value = value.replace(/^-/, '');
value = value.replace(/-$/, ''); range2.setValue(value);
This is example of a result:
"(22)road.CA" - "22-road-CA";
"22roadCA" - is not(eror).
If we working into google spreadsheets we could use formula's which I'm typed before, and in this case, results will be the:
"(22)road.CA" - "22-road-CA";
"22roadCA" - "22-road-CA".
So, how to create right code for it? Mb I should delete all signs, use looping method for check sign by sign, and insert my variant after some count of cell array?
Simple example :
var formulaTargetCell = SpreadsheetApp
.getActiveSpreadsheet()
.getActiveSheet()
.getRange(1, 1, 1, 1);
formulaTargetCell.setFormula('=ArrayFormula(replace(replace(regexreplace(K1:K&"""",""[-/,. ()]"",""""),4,0,""-""),8,0,""-""))');
//or
var formulaTargetCell = SpreadsheetApp
.getActiveSpreadsheet()
.getActiveSheet()
.getRange('B2');
formulaTargetCell.setFormulaR1C1('=ArrayFormula(replace(replace(regexreplace(K1:K&"""",""[-/,. ()]"",""""),4,0,""-""),8,0,""-""))');
There are still some kind of way to set formula in app script that documented in available API of Range

Categories