I am trying to change text in the html that is sent via email to a JS variable that I have defined. It is important that I am doing this in Google Scripts and have 2 files Code.gs & Email.html.
It seems like my html is not able to access the JS variable but I am not sure where I am going wrong here. I have referenced somewhat similar posts and tried a could different ways but cant get it to work. If anyone ha suggestions, that would be fantastic.
Code.gs
var JSname;
function Email() {
JSname = 'It works!'
var theEmail = 'myemail#gmail.com';
var theSubject = 'Email subject line';
var template = HtmlService.createTemplateFromFile('Email');
var message = template.evaluate().getContent();
MailApp.sendEmail({ to: theEmail, subject: theSubject, htmlBody: message });
return
}
Email.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<span id="HTMLname">[Text here]</span>
<script type="text/javascript" src="Code.gs">
document.getElementById("HTMLname").innerHTML = JSname;
</script>
</body>
</html>
Issue:
You're using a variable out of scope, simple as that
Fix:
Use template vars:
code.gs
function doGet(e) {
var template = HtmlService.createTemplateFromFile('Index'); // Or whatever you have
var JSname = 'It works!' // Ideally var names should start with lowercase
template.JSname = JSname // This is the IMPORTANT change
// Build and return HTML in IFRAME sandbox mode. (Copied from GS directly)
return template.evaluate()
.setTitle('Web App Window Title')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function Email() {
var theEmail = 'myemail#gmail.com';
var theSubject = 'Email subject line';
var template = HtmlService.createTemplateFromFile('Email');
var message = template.evaluate().getContent();
MailApp.sendEmail({
to: theEmail,
subject: theSubject,
htmlBody: message
});
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<span id="HTMLname"><?= JSname ?></span>
</body>
</html>
Source: https://script.google.com/u/1/home/start
Related
This is my first question here and I am pretty new to js and html so please excuse if I'm missing something obvious.
Goal: I want to create a script, that creates a Folder in your Google Drive but only if it's not already existing. In that folder it should create a .txt that contains certain information. After that, I want a new Tab to automatically open the URL of the newly created txt-file.
If I insert a normal URL in my .html (like "https://www.google.com") it all works perfectly fine. However I'm stuck at the part where the Apps Script hands over the grabbed Url of the newly created file to my html.
Any help is appreciated!
Google Apps Script Code (Code.gs):
function myFunction() {
var FData = "Very important Data"
var destFolder = DriveApp.getFoldersByName("Folder"); //create Drive folder if not already created
var destFolder = destFolder.hasNext() ?
destFolder.next() : DriveApp.createFolder("Folder");
var fileName = "Status.txt"; //create txt file in that folder and add data to it
var newFile = destFolder.createFile(fileName,FData);
var url = newFile.getUrl(); //?GIVE THIS URL TO openUrl.html?
var htmlOutput = HtmlService.createHtmlOutputFromFile('openUrl').setHeight(100);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Opening...');
}
HTML (openUrl.html):
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
var urlToOpen = url; //insert grabbed Url here
var winRef = window.open(urlToOpen);
google.script.host.close();
</script>
</head>
<body>
</body>
</html>
In your script, how about the following modification?
Google Apps Script side:
function myFunction() {
var FData = "Very important Data"
var destFolder = DriveApp.getFoldersByName("Folder");
var destFolder = destFolder.hasNext() ? destFolder.next() : DriveApp.createFolder("Folder");
var fileName = "Status.txt";
var newFile = destFolder.createFile(fileName, FData);
var htmlOutput = HtmlService.createTemplateFromFile('openUrl');
htmlOutput.url = newFile.getUrl();
SpreadsheetApp.getUi().showModalDialog(htmlOutput.evaluate().setHeight(100), 'Opening...');
}
HTML & Javascript side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
var urlToOpen = "<?!= url ?>";
var winRef = window.open(urlToOpen);
google.script.host.close();
</script>
</head>
<body>
</body>
</html>
When myFunction() is run, a dialog is opened by HTML including url using HTML template.
Reference:
HTML Service: Templated HTML
I am trying to create webapp with html service. Here is my code.
The code in code.gs file.
function doGet() {
return HtmlService
.createTemplateFromFile('userendhtml')
.evaluate();
}
function getData() {
var sss = SpreadsheetApp.openById('xxxx');
var rawData = sss.getDataRange().getValues()
var data = []
for (var i = 0; i< rawData.length; i++){
data.push(rawData[i])
}
return data
}
Now I want to access this data as javascript variable for further processing (for creating table with querying). The code in userendhtml.html is
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
var data2 = getData();
</script>
</body>
</html>
This doesn't store data to variable data2. So how to get data from spreadsheet in variable in javascript?
You want to use google.script.run in conjunction with withSuccessHandler(...)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
var data2;
google.script.run.withSuccessHandler(function(ret){
data2 = ret;
}).getData();
</script>
</body>
</html>
You could use the techniques found in the Templated Html reference that I gave you. But you could also do this:
<script>
var data2;
window.onload=function(){
google.script.run
.withSuccessHandler(function(dt){
data2=dt;
document.getElementById('myDiv').innerHTML=data2;
.getData();
}
</script>
The templated html approach loads on the server and this approach loads after the dom loads.
I just tested this example as a dialog
function dialogTest() {
var html='<div id="mydiv"></div>';
html+='<script>var data2;window.onload=function(){google.script.run.withSuccessHandler(function(dt){data2=dt;document.getElementById("mydiv").innerHTML=data2;}).getMtData();}</script>';
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), 'Dialog Test');
}
function getMtData() {
return 'Hello World';
}
code.gs
function showMonth() {
var recipient1 = 'user#gmail.com';
var subject = "email subject";
// send email using html page
var emailTemplate = HtmlService.createTemplateFromFile('file');
MailApp.sendEmail(recipient1, subject,'',{'htmlBody': emailTemplate.evaluate().getContent(), 'cc': '', 'bcc': ''});
}
file.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h2>My First Web Page</h2>
<p>My First Paragraph.</p>
<p id="displaymonth"> </p>
<script>
var d = new Date();
var mnth = getMonthDetails();
function getMonthDetails() {
switch (d.getMonth()) {
case 9 :
return "October";
break;
}
document.getElementById("displaymonth").innerHTML = "Current month is " + mnth;
</script>
</body>
</html>
Output in email:
My First Web Page
My First Paragraph.
I'm trying to get date and month in JS script tag and posting them to HTML content.
Later fetching the same HTML content using email template service of Google Apps Script and sending an email to user to show the current month.
When I run the code on other online editor like jsfiddle.net, it is showing the month details on the results page. However, I cannot get the expected result in the email upon running the code on Google Apps Script.
Let me know a way to fix my code to see the expected results. Thanks!
This way your email and your webapp get the same contents
Most of the contents comes from a text file that's written in html. And then in the function getContents() I append the line with the month in it. That function provides content to the doGet() and the sendEmail().
aq1.gs
function getContents() {
var folder=DriveApp.getFolderById('folderId');
var file=folder.getFiles().next();//assume only one
var contents=file.getBlob().getDataAsString()+Utilities.formatString('<p>This month is %s</p>',Utilities.formatDate(new Date(), Session.getScriptTimeZone(),"MMMM" ));//get content from file and append the date to it as a string
return contents;
}
function sendEmail() {
var recipient1 = 'recipient email';
var subject = "Combining Email and Website Contents";
var html=getContents();
MailApp.sendEmail(recipient1, subject,'',{htmlBody:html});
}
function doGet() {
return HtmlService.createHtmlOutputFromFile('aq5');
}
function launchDiaog() {
var userInterface=HtmlService.createHtmlOutputFromFile('aq5');
SpreadsheetApp.getUi().showModelessDialog(userInterface, "My Dialog");
}
aq5.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function() {
console.log('Ready State Function');
google.script.run
.withSuccessHandler(function(hl){
console.log(hl);
$('#mydiv').html(hl);
})
.getContents();
});
console.log("My Code");
</script>
</head>
<h1>Testing</h1>
<div id="mydiv"></div>
</html>
This is the contents of the ascii text file:
<h2>My First Web Page</h2><p>My First Paragraph.</p><p>My second paragrah</p>
But it could be anything upto 50MB
Try getting the date on the app script then passing it as a variable into your HTML file.
I don't think your client side js code will be executed by the Apps Script.
I have the following code:
code.gs:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('My Menu')
.addItem('Test', 'showTestForm')
.addToUi();
}
function showTestForm() {
var html = HtmlService.createHtmlOutputFromFile('TestForm');
SpreadsheetApp.getUi().showModalDialog(html, 'TEST');
}
function Test(formObject){
Logger.log("TEST")
var a = new Error( "Allready present "+ formObject);
a.error_code = 99;
Logger.log(JSON.stringify(a));
throw a;
}
TestForm.html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<base target="_top">
<script>
function onFailure(error) {
var keys = Object.keys(error);
alert(JSON.stringify(keys));
alert(JSON.stringify(error.message));
alert(JSON.stringify(error.error_code));
}
function onSuccess() {
alert("Success");
}
</script>
</head>
<body>
<input type="submit" value="Save" onclick="google.script.run.withFailureHandler(onFailure).withSuccessHandler(onSuccess).Test('1')" />
<input type="button" value="Close" onclick="google.script.host.close()" />
</body>
</html>
When I open TestForm from menu and press "Save" I've got following log from Logger:
[18-12-24 23:08:24:765 PST] TEST
[18-12-24 23:08:24:766 PST] {"message":"Allready present 1","error_code":99}
So I see, that error object have properties 'message' and 'error_code'. But in browser I've got following alerts:
["name"]
"Error: Allready present 1"
undefined
So I see, that recived error object has only one empty (i've checked) property "name". But if I but refer to the property "message, I've got string like in original object (but not the same). And it looks like that object haven't poperty "error_code".
What's the matter?
I thought you might like a complete working example as I know this stuff can be quite frustrating.
This a simple example templated HTML file that can be used as a dialog or a webapp. All it does is create a Google Doc file with todays date in the header and footer of each page and it puts the file into the same directory as the spreadsheet which contains the script. That's it. I use the Chrome Browser. I don't even care if my scripts won't run on another browser.
Here's the HTML: (FileName:'docwithdate.html')
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('resources') ?>
<?!= include('css') ?>
</head>
<body>
<?!= include('form') ?>
<?!= include('script') ?>
</body>
</html>
The Resources: (FileName: 'resources.html')
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
The CSS: (FileName: 'css.html')
<style>
body {background-color:#ffffff;}
input[type="button"]{padding:0 0 2px 0;}
</style>
The Form: (FileName: form.html) This is probably push the templating idea a little far.
<form id="myForm" onsubmit="event.preventDefault();processForm(this);" >
<input type="text" id="txt1" name="filename" />
<input id="btn" type="submit" value="Submit" />
</form>
The Javascript: [FileName: 'script.html')
<script>
function createFile(){
var name=document.getElementById('filename').value;
google.script.run
.withSuccessHandler(function(rObj){
var html='<br />Go To File:' + rObj.filename + '';
$(html).appendTo("body");
})
.createTemplatedGoogleDoc(name);
}
function getInputObject(obj) {//I'm probably doing something wrong here. But this is what I had to do to get the object with the properties that I desired. So if you have another way. Go for it.
var rObj={};
for(var i=0;i<Object.keys(obj).length;i++){
if(obj[i].type=="text"){
rObj[obj[i].name]=obj[i].value;
}
console.log('Object.keys(rObj): %s',Object.keys(rObj).join(', '));
}
return rObj;
}
function processForm(obj){
var fObj=getInputObject(obj);
var name=fObj.filename;
google.script.run
.withSuccessHandler(function(rObj){
document.getElementById("btn").disabled=true;
var html='<br />Go To File:' + rObj.filename + '';
$(html).appendTo("body");
})
.createTemplatedGoogleDoc(name);
}
console.log('My Code');
</script>
The Google Script: (FileName: Code.gs)
function onOpen(){
SpreadsheetApp.getUi().createMenu('My Menu')
.addItem("Open Templated Google Doc", 'showMyDialog')
.addToUi()
}
function createTemplatedGoogleDoc(name){
Logger.log(name);
var doc=DocumentApp.create(name);//Creates a google doc
var fldrs=DriveApp.getFileById(SpreadsheetApp.getActive().getId()).getParents();
while(fldrs.hasNext()){
var fldr=fldrs.next();
if(fldr.getName()=="Create Templated Google Doc App"){
var folder=fldr;
}
}
Drive.Files.update({"parents": [{"id": folder.getId()}]}, doc.getId());//puts doc file into same directory as the spreadsheet that contains the script
doc.addHeader().appendParagraph(Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "E MMM dd, yyyy"));
doc.addFooter().appendParagraph(Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "E MMM dd, yyyy"));
//doc.getBody().getChild(0).removeFromParent();
doc.saveAndClose()
var rObj={url:doc.getUrl(),filename:doc.getName()}
return rObj;
}
function showMyDialog(){
var ui=HtmlService.createTemplateFromFile('docwithdate').evaluate();
SpreadsheetApp.getUi().showModelessDialog(ui, 'My Doc with Date');
}
function doGet(){//if you want a web app this is helpful
return HtmlService.createTemplateFromFile('docwithdate').evaluate();
}
function include(filename){//this is the include that the template uses
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
It's a pretty simple script. I hope it helps you get a start.
In accordance with the proposal of #TheMaster it is necessary to do this:
code.gs
function Test(formObject){
var a = new Error( JSON.stringify({msg:"Allready present "+ formObject,code:99}));
throw a;
}
TestForm.html
// removing "Error: " from message string to get our json back
var json = error.message.replace("Error: ",'')
var msg = JSON.parse(json).msg;
var code = JSON.parse(json).code;
That is, we put json into the attribute message of the Error object, and then, by cutting our json, we parse it and get the necessary values.
This is not exactly the answer to the question, but a good way to solve the problem.
I am testing putting a text editor on my page and storing it as part of a JSON object.
HTML
<!DOCTYPE html>
<html>
<head>
<script src="http://tinymce.cachefly.net/4.0/tinymce.min.js" type="text/javascript"> </script>
<script type="text/javascript">
tinymce.init({
selector: "textarea"
});
</script>
<link rel="stylesheet" href="/jquery.mobile-1.3.2.min.css"/>
<script src="/jquery-1.9.1.min.js"></script>
<script src="/jquery.mobile-1.3.2.min.js"></script>
</head>
<body>
<form method="post" action="formSubmit.js">
<textarea name ="editor"></textarea>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
JS
$(document).ready(function () {
var text = $("editor").val();
var name = "project name";
var id = 5;
var item = new item(name, text, id);
var itemArray = localStorage.items;
if (itemArray == undefined) {
itemArray = [];
} else {
itemArray = JSON.parse(itemArray);
}
itemArray.push(item);
localStorage.items = JSON.stringify(itemArray);
});
I want to be able to store item in a JSON object. When I run this I receive a "not-well formed" error at line 1 of the Javascript. It's a very simple program I'm running and can't seem to pinpoint what is causing the error. Is the JSON done incorrectly or are scripts in my HTML header causing issues?
$("editor") is looking for an html tag called 'editor'. you probably want to attach an id attribute to your and do $('#editor')