Is there anyway to verify a google spreadsheets ID's - javascript

So don't crucify me too badly if this is a dumb question,
But I've been dabbling in Google App Scripts, mainly its uses within Google sheets.
Generally when I've been using openById()
If it's an ID that might change regularly, I'll put it at the top of my script and add notes on how to edit (for the user i hand sheet over to, or for me as a reminder if i've not worked on it for a bit and i forget). If's pretty stangnant and not likely to change, I'll just declare it as a var.
I was thinking it's a bit more user friendly to have a "settings" sheet within the spreadsheet and the user inputs the settings. Rather than having to go into script editor to edit things.
But even via sheet, or script editor, a single thing added or removed in the wrong place can cause havock, like a space or /
At least with a "settings" sheet, you can use data validation and regular expressions to control and reject what the user inputs.
So I guess my question is Google Sheets ID's seem alien to me, bar length, and I was wondering is there any way to validate the ID's using regular expressions or something, rather than checking the ID server side.
Thanks :)

You can also use openByUrl() in your scripts, so users can just paste a link.
but if you must validate the ID:
ss = SpreadsheetApp.getActiveSpreadsheet();
function validate(){
//"sheetRef" is the name of the cell where you enter the id
//this function takes the string value of "sheetRef"
//and replaces it with the validation result.
var sheetRefCell = ss.getRangeByName("sheetRef");
var sheetRefString = sheetRefCell.getValue();
var validationResult = '{' + sheetRefString + '}';
try {
validationResult = validationResult +
' \n $ references: \n [' +
SpreadsheetApp.openById(sheetRefString).getName() +
']';
}
catch (e) {
validationResult = validationResult +
' \n $ is an invalid reference: \n [' +
e +
']';
}
finally {
sheetRefCell.setValue(validationResult);
}
}
when you run this it will replace the value entered in your 'sheetRef' (ID) cell with the validation result message. I recommend that you also add a time-based trigger to contininuously revalidate your ID.
Then you can add another cell to your spreadsheet which will extract the validated ID from 'sheetRef'. This cell should contain the formula:
= IF (IFERROR( SEARCH( 'invalid' , sheetRef ), 0 ) > 0,
"Invalid",
IFERROR( REGEXEXTRACT( sheetRef,"{(.*?)}" ), "Undetermined" )
)
So the cell with the above formula will EITHER display a valid id or "Invalid"/"Undetermined".

Related

Concate String to a formula in app script

I have a values in google sheet and the format is =+40,-58. This give me ERROR! because the sheet is taking it as formula.
I can manually edit this by adding ' single qoute before equal sign but when i append qoute using script it append qoute with ERROR!.
Tried multiple thing like getting cell type, convert it to string.
Tried set formula method but it appends another equal sign before the cell value
please check the code below
if (//my condition){
sheet.getRange(i,col_in+1).setValue("'"+colvalue)
I am looking for possible solutions like, how can I get the actual value of the cell from fx
or
How can i append a single quote with the cell value instead of appending quote with ERROR.
please see the screenshot of the sheet
Descrition
Because the formula is giving "#ERROR" you need to getFormula and use setValue
Script
function test() {
let cell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").getRange("A6");
let value = cell.getFormula();
if( value !== "" ) {
console.log("formula = "+value);
cell.setValue("'"+value);
}
}
Console.log
7:30:31 AM Notice Execution started
7:30:31 AM Info formula = =+52,-64
7:30:32 AM Notice Execution completed

Auto Log Wordcount from Docs to Sheets

Having a lot of trouble finding this and as a very beginner programmer, I can't quite troubleshoot my way through this.
What I want to do:
Automatically log the word count of a google doc in a google sheets cell.
The code I've been playing with to try and make it happen that is probably super wrong:
function countWords() {
var doc = DocumentApp.openByURL().getBody().getText();
var punctuationless = doc.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()"?“”]/g," ");
var finalString = punctuationless.replace(/\s{2,}/g," ");
var count = finalString.trim().split(/\s+/).length;
return count;
Ideally, what I'd like to do is, in sheets, set it up so there's a column with links to google docs and be able to just put in a function that will return the wordcount from that doc.
Answer:
You can not create a custom function to do this, as reading another document requires authentication. You can however do this with an in-sheet button which runs the script.
More Information:
As per the documentation on custom functions, it is not possible to run methods which require authentication such as DocumentApp:
Unlike most other types of Apps Scripts, custom functions never ask users to authorize access to personal data. Consequently, they can only call services that do not have access to personal data
As a result, you will instead have to manually run the script - but this can be done from a button in the Sheet.
Code:
Assuming that you have the Document links in column A and wish for the word count to be in column B (starting in row 2):
function countWords() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var linkRange = ss.getRange("A2:A");
try {
linkRange.getValues().forEach(function(cell, index) {
if (cell[0] == "") {
throw "Cell A" + (index + 2) + " is empty"
}
let doc = DocumentApp.openByUrl(cell[0]).getBody().getText();
let count = (doc.match(/\b\S+\b/g) || []).length;
ss.getRange(index + 2, 2).setValue(count);
});
}
catch (err) {
console.log(err);
return;
}
}
Rundown of this function:
Open the sheet containing the document links (remember to change the sheet name!)
Get the range of links down column A
Loop through each link and obtain the Document's text
Obtain all instances of word-boundary/non-whitespace/word-boundary in the document, puts them all into an array, and gets the length of the array.
In this step, if the document is empty, then an empty array is given
Sets the cell in column B adjacent to the link to the result of the count.
This is all wrapped inside a try/catch so that the script stops execution when it reaches an empty cell in column A.
Assigning to a Button:
Now, you can create an in-sheet button which will run the script whenever you click it.
Go to the Insert > Drawing menu item and create a shape; any shape will do, this will act as your button.
Press Save and Close to add this to your sheet.
Move the newly-added drawing to where you would like. In the top-right of the drawing, you will see the vertical ellipsis menu (⋮). Click this, and then click Assign script.
In the new window, type countWords and press OK.
Now, each time you click the button, the script will run.
Visual Example:
References:
Custom Functions in Google Sheets | Apps Script | Google Developers

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!

Automatically replace dots with commas in a Google Sheets Column with Google Script

I have a WooCommerce store, which is connected with Zapier to a Google spreadsheet. In this file, I keep track of the sales etc. Some of these columns contain -obviously- prices, such as price ex VAT, etc. However, for some reason the pricing values are stored in my spreadsheet as strings, such as 18.21.
To be able to automatically calculate with these values, I need to convert values in these specific columns to numbers with a comma as divider. I'm new to Google Script, but with reading some other post etc, I managed to "write" the following script, which almost does the job:
function stringIntoNumber() {
var sheetActive = SpreadsheetApp.openById("SOME_ID");
var sheet = sheetActive.getSheetByName("SOME_SHEETNAME");
var range = sheet.getRange("R2:R");
range.setValues(range.getValues().map(function(row) {
return [row[0].replace(".", ",")];
}));
}
The script works fine as long as only values with a dot can be found in column R. When values that belong to the range are changed to values with a comma, the script gives the error:
TypeError, can't find the function Replace.
Select the column you want to change.
Goto Edit>Find and Replace
In Find area put "."
in Replace with area put ","
The error occurs because .replace is a string method and can't be applied to numbers. A simple workaround would be to ensure the argument is always a string, there is a .toString() method for that.
in your code try
return [row[0].toString().replace(".", ",")];
The locale of your spreadsheet is set to a country that uses commas to seperate decimal places. Zapier however seems to use dots and therefore google sheets interprets the data it gets from Zapier as strings since it can't interpret it as valid numbers.
If you change the locale to United States (under File/Spreadsheet settings) it should work correctly. But you may not want to do that because it can cause other issues.
You got a TypeError because the type was number and not string. You can use an if statement to check the type before calling replace. Also you should convert the type to 'number' to make sure it will work correctly independent of your locale setting.
range.setValues(range.getValues().map(function(row) {
if(typeof row[0] === "string") return [Number(row[0].replace(",", "."))];
else return row;
}));
In this case I convert , to . instead of the other way around since the conversion to number requires a ..
Click on Tools > Script Editor.
Put this on your macros.gs (create one if you don't have any):
/** #OnlyCurrentDoc */
function ReplaceCommaToDot() {
var range = SpreadsheetApp.getActiveRange();
var col = range.getColumn();
var row = range.getRow();
function format(str) {
if(str.length == 0) return str;
return str.match(/[0-9.,]+/)[0]
.replace('.','')
.replace(',','.');
}
var log = [range.getRow(), range.getColumn()];
Logger.log(log);
var values = range.getValues()
for(var row = 0; row < range.getNumRows(); row++){
for(var col = 0; col < range.getNumColumns(); col++){
values[row][col] = format(values[row][col]);
}
}
range.setValues(values);
}
Save. Go back to the spreadsheet, import this macro.
Once the macro is imported, just select the desired range, click on Tools > Macro and select ReplaceCommaToDot
Note: This script removes the original ., and replaces , by .. Ideal if you are converting from US$ 9.999,99 to 9999.99. Comma , and whatever other text, like the currency symbol US$, were removed since Google Spreadsheet handles it with text formatting. Alternatively one could swap . and ,, like from US$ 9.999,99 to 9,999.99 by using the following code snippet instead:
return str.match(/[0-9.,]+/)[0]
.replace('.','_')
.replace(',','.')
.replace('_',',');
An alternative way to replace . with , is to use regex functions and conversion functions in the Sheets cells. Suppose your number is in A1 cell, you can write this function in any new cell:
= IF(REGEXMATCH(TO_TEXT(A1), "."), VALUE(REGEXREPLACE(TO_TEXT(A1), ".", ",")), VALUE(A1))
These functions do the following step:
Convert the number in the target cell to text. This should be done because REGEXMATCH expects a text as its argument.
Check if there is a . in the target cell.
If there is a ., replace it with ,, and then convert the result to a number.
If there is no ., keep the text in the target cell as is, but convert it to a number.
(Note : the Google Sheets locale setting I used in applying these functions is United States)
I have different solution.
In my case, I`m getting values from Google Forms and there it is allowed use only numbers with dot as I know. In this case when I capture data from Form and trigger script which is triggered when the form is submited. Than data is placed in specific sheet in a specific cell, but formula in sheet is not calculating, because with my locale settings calculating is possible only with a comma not dot, that is coming from Google Form.
Then I use Number() to convert it to a number even if it is already set as a number in Google Forms. In this case, Google Sheets script is converting number one more time to number, but changes dot to comma because it is checking my locale.
var size = Number(sizeValueFromForm);
I have not tested this with different locale, so I can`t guarantee that will work for locale where situation is opposite to mine.
I hope this helps someone. I was looking for solution here, but remembered that some time ago I had similar problem, and tried this time too and it works.
=IF(REGEXMATCH(TO_TEXT(F24);"[.]");REGEXREPLACE(F24;"[.]";",");VALUE(F24))
Works for me
If find dot replace with comma if not, put value

Create javascript string with conditional and non conditional variables

I'm creating a single string using some defined variables like so:
var name = 'John';
var business = 'Google';
var email = name + ' registered the business ' + business;
In reality this is from a form submission so the variables will be set in a form and sent to my NodeJS backend to create this string. The user may or may not enter a message. I've created an if statement to add it to the string if they have:
if (message) email += '<br /><br />Message: ' + message;
The problem is when I expand this logic, it can get very messy. For example if I want to add several conditional variables to various points in the middle of the original string. Is there a way to do the conditional logic inside the initial string build?
Use a ternary operator. It can still get messy, but it reduces "if" everywhere.
var email = name + ' registered ' + business
+ (message ? '<br /><br />Message: ' : '') // conditional line
+ more_stuff...;
There are many ways you could structure the code to clean things up. A simple solution would be creating an object that keeps track of your various inputs, and then you could loop through that object to append all necessary items.
For example:
var obj = {
message: messageField,
messageTwo: messageTwoField
}
for (keys in obj){
if (key == message && obj.key) {
//append the string to a specific place
}
}
There are many ways to potentially solve this, but by storing everything in one object that can help to clean things up. Also, the if statement is conditional based on the key name and if there is a value assigned to that key name. This of course is just my opinion on how you could approach this, the size and complexity of the app could greatly change this answer.

Categories