I am currently learning Apps Script fundamentals. I've encounter a method:
evaluate()
e.g.
const htmlServ = HtmlService.createTemplateFromFile("main");
const html = htmlServ.evaluate(); //
Within the reference it says:
It evaluates template and returns an HtmlOutput object.
My question: Does evaluate() has anything to do with security internally in Apps Script? Any relationship with HTML entities and its escaping? I want to clear this out.
Thanks.
evaluate() just injects data to your HTML templates. AFAIK it has nothing to do with the security.
The most common use case of this mechanism is when you have (nicely styled :)) HTML template that you want to have dynamic data. For example you have daily report that you want to display on a HTML page or send by email that has HTML body. But each day your Daily Total Revenue is different. You would do something like this:
<!-- Inside index.html file -->
<html>
<div class=my-class">
<p>Daily Total Revenue is: <?= dailyTotalRevenueVar ?>.</p>
</div>
</html>
// Inside Code.gs file
const template = HtmlService.createTemplateFromFile("index");
template.dailyTotalRevenueVar = 1000000; // Add a property to the template
const htmlOutput = template.evaluate(); // Replace var in HTML with actual value 1000000
Logger.log(htmlOutput.getContent()); // or return as a result in doGet()
You have many more options besides the simple value replacing, you can skip the entire HTML block if array has zero length, you can make a for loop to fill the select options...
Take a look at this page (toggle between .gs and .html view in code examples)
https://developers.google.com/apps-script/guides/html/templates
For more info about doGet and publishing GAS project as a web application visit this page:
https://developers.google.com/apps-script/guides/web
Related
I have written a script that creates a new "Report" every time it is ran. This is done by generating a new Google Spreadsheet, which then displays a filtered set of values based off inputs in the original spreadsheet it is tied to. Below is the code:
Report Script
The script is activated by a custom menu bar. An example of the menu bar is here below:
Menu Bar Code
Upon clicking into the custom menu bar, I would like the newly generated "report" spreadsheet to open. Since this script creates a new spreadsheet each time it is ran, the URL will be different each time, therefore, I am not sure how to incorporate the variable URL into an HTML file. Below are some lines of code I have used to open files upon using the custom menu bar:
HTML File Code
In the above image, "+ ssNewURL +" is where the known URL to the desired destination would go. I attempted to reference a variable I used earlier (ssNewURL) which gets the URL of the newly generated sheet, but it did not work. I have tried to get around the formatting issue of the HTML file which requires the URL to be a string; I've tried changing locations of double "" quotations,
and single '' quotations. Whatever I have tried, the HTML file refuses to open.
I am extremely new to coding, I understand the logic behind it, however, I am very unfamiliar with every function/formatting of Google Scripts coding.
Any suggestions or workarounds for getting the HTML part of the code to open the dynamically changing URL would be greatly appreciated!
When you call window.open(), the URL also needs to be enclosed in quotation marks.
let htmlOutput = HtmlService.createHtmlOutput(
"<script type='text/javascript'>" +
"window.open('" + url + "', '_blank');" +
"google.script.host.close();" +
"</script> "
);
Another option would be to pass the URL of your spreadsheet to the HtmlTemplate object as a property:
let template = HtmlService.createTemplateFromFile("popup");
template.url = url;
return SpreadsheetApp.getUi().showDialog(template.evaluate());
Calling evaluate() on an HtmlTemplate object will execute the embedded JS code and place all variables you passed to the template in scope.
popup.html
<body>
Opening your spreadsheet...
<input type='hidden' id="hidden-field" value='<?!= url ?>' />
<script>
var url = document.getElementById("hidden-field").value;
window.open(url, "_blank");
google.script.host.close();
</script>
</body>
I would like to have a google sheet that when you pick something on a google sheet it brings up an html file on a new google tab that has info from the google sheet. I am using the code below as a quick test to see if this is possible.
Right now I have a menu item that calls myFunction(), then I would like that to bring up the new html page. This doesn't come close to working, as it just enters and exits myFunction and no html page. So was wondering if anyone knows if this is possible. If so can you give me some hints on how to do it.
code.gs
function myFunction(){
HtmlService.createTemplate('page');
};
page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<title>Hello<\title>
</body>
</html>
Change myFunction() to doGet(), and you need to return the HtmlService from the doGet function. Also, the statement inside the doGet() function is different than what you currently have.
Your myFunction() function should look like this
function doGet() {
return HtmlService.createTemplateFromFile('page').evaluate();
}
doGet() is a special function that Google Apps Script web app scripts should handle any GET requests.
For more information, please refer to one of these guides:
https://developers.google.com/apps-script/guides/html/templates
https://developers.google.com/apps-script/guides/html
This is absolutely possible.
What you want to implement is a web app.
Simple Example
function doGet() {
textOutput = ContentService.createTextOutput("Hello World! Welcome to the web app.")
return textOutput
}
Put this in a script file and then deploy the script as a web app - instructions. The deploy process will give you a link with which you can visit the web app and see your text output.
What apps script does is that every time someone visits the URL, the doGet function is run.
HTML Example
function doGet(){
let HTMLString = "<style> h1,p {font-family: 'Helvitica', 'Arial'}</style>"
+ "<h1>Hello World!</h1>"
+ "<p>Welcome to the Web App";
HTMLOutput = HtmlService.createHtmlOutput(HTMLString);
return HTMLOutput
}
As you have already seen, HtmlService is what to use to serve up HTML.
Linking to Spreadsheet
The best way IMO to approach this is:
Create a spreadsheet.
Create the script from the spreadsheet menu - this ensures that the script and sheet are linked.
Decide how you want to present the information from the Spreadsheet and get it with something like:
let file = SpreadsheetApp.getActive(); // getActive only possible if script and sheet are linked
let sheet = file.getSheetByName("Sheet1");
let range = sheet.getDataRange();
let values = range.getValues();
Figure out how to translate that into HTML.
Write your doGet function.
Deploy
Profit!
Docs
Google Apps Script Web Apps
HTML Service
Spreadsheet Service
For a Google site, I want a page to display content based on the url parameters.
Eg. http://sites.google.com/../mypage?id=123
Then I want to make a HTTP request using the id and display the result on the page.
Or I want to use App Scripts to perform something and display the result on the page.
How can I do so?
Use on Google app script
function doGet(e){
// id in your Url. example : http://sites.google.com/../mypage?myidok=123
var element - e.parameters.myidok
// code
// your app
}
See this answer for an example of serving multiple html pages using HtmlService. The basic idea is to write doGet() to accept a query parameter that it will use to select which html page to serve.
Suppose I have boo function inside an external JavaScript file, from domain http://localhost/file.js:
file.js:
function boo() {
return 1;
}
How can I call the boo function from content script in chrome extension?
You'll need to run a content script that creates and injects a <script> element that calls the page's boo() function.
Your content script should have something alone the lines of:
function runBoo() {
var myBoo = document.createElement('script');
myBoo.id = 'myBoo'; //helpful for removing the element later, not required to work
myBoo.innerText = 'boo();'
document.body.appendChild(myBoo); //if you plan on calling boo() multiple times, don't forget to delete the previously added myBoo elements
}
window.onload = function() {
//call runBoo() from content whenever you want to run the page's boo() function
runBoo();
}
According to this doc from Mozilla:
Content scripts can access the DOM of a page, of course, just like any
scripts that the page has loaded (page scripts). But content scripts
are insulated from page scripts:
content scripts don't see any JavaScript objects added to the page by
page scripts
if a page script has redefined the behavior of some DOM object, the
content script sees the original behavior.
Reasons:
it means that content scripts don't leak objects to web pages,
potentially opening up security holes.
it means that content scripts can create objects without worrying
about whether they might clash with objects added by page scripts.
Update
#Xan was right! thanks Xan.
if you need to interact with a function added by other page script, messaging between content script of your add-on and the page script is like this:
// main.js
var tabs = require("sdk/tabs");
var mod = require("sdk/page-mod");
var self = require("sdk/self");
var pageUrl = self.data.url("page.html")
var pageMod = mod.PageMod({
include: pageUrl,
contentScript: "console.log(unsafeWindow.foo);"
})
tabs.open(pageUrl);
where foo is a variable added by a page script.
I have a Google Apps Script gadget that is embedded in a Google Sites page. I would like to pass the gadget a page parameter, such that when the page is opened with URL like:
https://sites.google.com/a/mydomain/mysite/mypage?myparameter=1
I can access the value of the page parameter in the Apps Script gadget code like so:
function doGet(e) {
var app = UiApp.createApplication();
app.add(app.loadComponent("MyComponent"));
var myparam = e.parameter.myparameter;
return app;
}
Currently, the value of e.parameter.myparameter is coming back as null. Is there a way to setup my Apps Script to support this? Any approaches are welcome.
Maybe the link bellow will help you - I have not tried it myself yet...but I will try it out in the next days.
http://code.google.com/p/google-apps-script-issues/issues/detail?id=535
I posted this on the code.google.com page linked in the accepted answer, but the way to have parameters passed through to Apps Script is by adding "https://sites.google.com/feeds" to the Apps Script scope. (See this site for information about how to add explicit scopes.) Once this scope is added, the following works:
in Code.gs:
function doGet(e) {
var htmlTemplate = HtmlService.createTemplateFromFile("page");
htmlTemplate.urlParams = e.parameters;
return htmlTemplate.evaluate();
}
in page.html:
...
<head>
...
<script>urlParams = <?!= JSON.stringify(urlParams) ?>;</script>
</head>
...
urlParams is now available as a variable in your JS code in the following form:
urlParams = { key1: [value1, value2, ...], key2: [value1, value2] }
This example describes a parameter as "&name=value" however I have not been able to get it working in either a Google Apps Site, or in a Personal Google Site. (which seem to handle authentication in different ways)
The example seems to work fine when I hard-code the value so maybe I am just not parsing it right or something, I will try to follow up here when I understand this better but I also have not yet found adequate explanations of these features.
One Hypothesis is that Google changed something, I note the menu structure does not seem to match what I assume it use to be since I see many references to a [share] button/menu.