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")');
Related
I know what I'm doing is not good, and we're working on changing it for the better, but in the meantime I need to make do with what I have...
I have a rather large Google Sheet that more or less is acting as a DB. It's fed data from GForms and then that data is used on a number of other sheets for various purposes (e.g. reporting, selective info sharing to certain groups, etc.) mostly through querys and importranges.
The editing of the main sheet is restricted to only a handful of people, including myself. One of the others has made some changes (deleting some columns) that are going to break any queries or imports because the importrange won't catch the column changes and auto-update the range.
The changes made are actually good and worth keeping, so I don't want to revert them.
Is there a way for me to easily find out all of the sheets that use the main one so that I can update the affected formulas? In updating, I'll also need to find a way to avoid this happening again (I think I can do this by setting the range references using address? But that's future me's problem...)
Thanks in advance!
Find (Ctrl-H) gives the option to "Also search within formulae"
You can use this to search for references to a particular sheet eg searching "sheet1!" will find all cells that reference sheet1
Note this may not work if named ranges are defined, you may need to search for the named range as well.
To find dependencies between sheets in different documents (or even the same document) use the following script to search for references to a given doc id (eg within IMPORTRANGE) eg:
FindFormulae("1XgTuET_dJKP-i4JppvQQFI047-ZKP-i4o4bhE-K1lF-o")
function FindFormulae(keyword) {
// searches all google docs for formulae containing the given keyword
// outputs to sheet "output"
// may take a while if you have a lot of docs, and could timeout (5 minutes)
// if timeout just run the script again, it skips any docs already checked
// to cancel script execution go to https://script.google.com/home/executions
// Feb 2020 www.enex.net
var sheetOut= SpreadsheetApp.getActiveSpreadsheet().getSheetByName("output");
docsAlreadyChecked = sheetOut.getRange(1,1,sheetOut.getLastRow(),1).getValues();
var files = DriveApp.getFiles();
while (files.hasNext()) { // loop thru files
var file = files.next();
if (file.getMimeType() != "application/vnd.google-apps.spreadsheet") continue; // only process spreadsheets
docURL =file.getUrl();
docName =file.getName();
//Logger.log('Starting.. ' + docName + '\n' + docURL + '\n');
//DaysSinceUpdate = (new Date() - file.getLastUpdated())/(1000 * 60 * 60 * 24)
//if ( DaysSinceUpdate > 90 ) continue; // skip if file hasn't been updated for more than 7 days
if (docsAlreadyChecked.toString().indexOf(docName)>0) continue; // skip if already done // note this needs fixing as will fail if one doc is substring of another
var ssIn = SpreadsheetApp.openByUrl(docURL); // open doc
for (var i = 0; i < ssIn.getNumSheets(); i++) { //loop thru sheets in doc
sheetname = ssIn.getSheets()[i].getName();
//sheetid = ssIn.getSheets()[i].getSheetId();
if (ssIn.getSheets()[i].getMaxRows()==0) continue; //skip if no rows (eg if it's a chart)
ListFormulae(docURL, sheetname, keyword);
} // end for loop thru sheets
//strHyperlink = "=hyperlink(\"" + docURL + "#gid=" + ssIn.getSheets()[i].getSheetId() + "\", \"" + docName + "\")";
strHyperlink = "=hyperlink(\"" + docURL + "\", \"" + docName + "\")";
sheetOut.appendRow([strHyperlink, '', '', 'finished search ' + new Date() ]);
} // end while loop thru files
}
function ListFormulae(docURL, sheetname, keyword) {
var ssIn = SpreadsheetApp.openByUrl(docURL);
var sheetIn = ssIn.getSheetByName(sheetname);
//var sheetIn = ssIn.getSheetId(sheetid);
//var sheetname = ssIn.getSheetName();
var sheetOut= SpreadsheetApp.getActiveSpreadsheet().getSheetByName("output");
LastRow = sheetIn.getLastRow();
LastColumn = sheetIn.getLastColumn();
if (LastRow==0 && LastColumn==0) return; // nothing in sheet
var range = sheetIn.getRange(1, 1,LastRow , LastColumn);
var formulas = range.getFormulas();
for (var i in formulas) {
for (var j in formulas[i]) {
if (formulas[i][j]=="") continue; // skip if no formula
if (formulas[i][j].search(keyword) == -1) continue; //skip if keyword not found
strHyperlink = "=hyperlink(\"" + docURL + "#gid=" + sheetIn.getSheetId() + "\", \"" + ssIn.getName() + "\")";
rownum = parseInt(i)+1;
colnum = parseInt(j)+1;
sheetOut.appendRow([strHyperlink, sheetname, 'R' + rownum + 'C' + colnum, "'" + formulas[i][j]]);
}
}
}
I'am very new in gas.
The scenario is this :
Having a spreadsheet with the list of recipient and their names, I want to automate and customize the body of the email writing on the top "Dear {name}".
How can I pass the variable into the Htmlbody option?
Here is part of the code... Thanks in advance.
var ss = SpreadsheetApp.openById("xxxxxxxxxxxxxxxxxxxx").getSheets()[0];
var rng = ss.getRange(2, 1, ss.getLastRow()-1, 8);
var rngvls = rng.getValues();
//
for (var i = 0 ; i<rngvls.length; i++){
var name= ss.getRange(i + 2, 5, 1, 1).getValue();
GmailApp.sendEmail(dest, ogg, body,{name:nam, attachments: [fail.getAs(MimeType.PDF)], htmlBody : <html><h1>here is the header</h1> and here the name
</html>});
The values are already in rngvls. Using the method getValue() in a loop isn't very good for performance.
You can add the name to a string containing the html using concatenation.
Try this:
for (var i = 0 ; i<rngvls.length; i++){
var name = rnglvls[i+1][4];
var html = "<html><h1>here is the header</h1>"+name+"html";
GmailApp.sendEmail(dest, ogg, body,{name:nam, attachments: [fail.getAs(MimeType.PDF)], htmlBody : html});
}
You can pass HTML formatting into the script by setting an HTML variable and then using that variable in the optional MailApp arguments. You can also use other variables within the body using this approach.
It should be noted that the GmailApp class is more likely to require a re-authorization because it can access a user's inbox, so if all you're doing is sending mail the MailApp class is the recommended approach.
var1 = ...
var2 = ...
var3 = ...
var html = '<body>' +
'<p>Message.</p>' +
'<p><b>Variable 1: </b>' + var1 + '</p>' +
'<p><b>Variable 2: </b>' + var2 + '</p>' +
'<p><b>Variable 3: </b>' + var3 + '</p>' +
'</body>';
MailApp.sendEmail(recipient, subject, {htmlBody:html});
Use the Drive service and get the export link.
var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+docid+"&exportFormat=html";
var param = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()}
};
var htmlBody = UrlFetchApp.fetch(url,param).getContentText();
}
Here is a script that you can use if you don't need to send too many emails messages (because it's rather slow), it uses a Google doc as a template with a few placeholders and creates a temporary copy of it that is converted to HTML and sent as a message body.
All the features available in Google docs are correctly translated in HTML, including images, fonts etc...
Some formatting are slightly modified (image alignment for example) but nothing to really worry about.
If you are planning to send many messages you might need to create an automated process to send the messages in smaller bunches on a timer trigger but that would be out of subject here.
Code :
function customizeHTMLMessage() {
var templateId = '1aZAgVbvZYD1JcoLqv8x-A5knHLrVNOfEyGh_O-06dgg';// the template doc with placeholders
var docId = DriveApp.getFileById(templateId).makeCopy('temp').getId();
var doc = DocumentApp.openById(docId);// the temp copy
var body = doc.getBody();
var items = ['#day#','#starter#','#main course#','#dessert#'];// the placeholders in this example
var values = ['Monday','Smoked fish','Beef steak','ice cream'];
for(var n = 0;n<items.length;n++){
Logger.log(items[n]+' to replace with '+values[n]);// check in the log
body.replaceText(items[n],values[n]);// update the temp doc
}
doc.saveAndClose();// save changes before conversion
var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+docId+"&exportFormat=html";
var param = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()}
};
var htmlBody = UrlFetchApp.fetch(url,param).getContentText();
var trashed = DriveApp.getFileById(docId).setTrashed(true);// delete temp copy
MailApp.sendEmail(Session.getActiveUser().getEmail(),'test','html body',{htmlBody : htmlBody});// send to myself to test
}
note : this template doc is shared (view only) you can make a copy to test it.
Edit : screen capture in 2 different mail readers.
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
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") {
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:*\")");
_