Still new to Google Apps Script and I'm struggling connecting my Apps Script to my html file. As you can see in my Apps Script code below I've created a loop within Apps Script and for each iteration of the for loop I'd like to create a new heading in the html script, hence the "<?= question =>" scriplet linking to the Apps Script. Can anyone help me here?
Apps Script:
const name = "Name"
//This is calling the html template
function doGet() {
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var range_in_q = ws.getRange("A1:E" + ws.getLastRow()).getValues();
typeof(Logger.log(range_in_q));
Logger.log(range_in_q.length);
for (i = 0; i<range_in_q.length - 1; i++) {
var questions = range_in_q[i + 1][0];
var answers = range_in_q[i + 1][1];
Logger.log(questions);
Logger.log(answers);
return HtmlService.createTemplateFromFile('index').evaluate();
}
}
function includeExternalFile(filename) {
return HtmlService.createTemplateFromFile(filename).getContent();
}
Html Code:
<html>
<head>
<base target="_top">
</head>
<body>
<h1><?= name ?></h1>
<? for (let i=0; i<test; i++){ ?>
<h1> <?= questions ?></h1>
<? } ?>
<h1>This page was served through HtmlService!</h1>
</body>
</html>
Modification points:
In your script, when return HtmlService.createTemplateFromFile('index').evaluate(); is run in the loop, the function is finished.
name, questions and answers are not used in HtmlService.createTemplateFromFile('index').evaluate().
When the loop process is used in the HTML template, the process cost becomes high. Ref (Author: myself)
When these points are reflected in your script, how about the following modification?
Google Apps Script side:
const name = "Name"
function doGet() {
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var range_in_q = ws.getRange("A1:E" + ws.getLastRow()).getValues();
// I modified the below script.
var questions = range_in_q.map(([a]) => `<h1>${a}</h1>`).join("");
var html = HtmlService.createTemplateFromFile('index');
html.name = name;
html.questions = questions;
return html.evaluate();
}
HTML side:
<html>
<head>
<base target="_top">
</head>
<body>
<h1><?= name ?></h1>
<?!= questions ?>
<h1>This page was served through HtmlService!</h1>
</body>
</html>
From your showing script, in this modification, answers is not used. Because I cannot know your expected situation using answers. Please be careful about this.
Note:
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
References:
HTML Service: Templated HTML
Benchmark: Process cost for HTML Template using Google Apps Script (Author: me)
Related
My issue is, I'm using the yiono SCRIPT sql library and trying to integrate it with HTML but am having trouble with 2 pieces. Everything else is working beautifully.
For example
I want to make an HTML form to update the 'Pro' value on the row that 'ID' = '1'
It works beautifully when I run the function in IDE, but I don't know the best way to put these in as variables from an HTML page. I tried some silliness with GET requests but couldn't get it to work.
function update_row(){
var SQL = new gSQL();
SQL.DB('*redacted*').TABLE('DAILY-DATA').UPDATE('Pro').WHERE('ID', '=', '1').VALUES('KAOS').setVal();
}
Problem 1: Get form input into .WHERE('ID', '=','from_html_form') and I'd like to do it within the Google environment by way of web app.
Minimal Reproducible Example
Here is the function
Here is the result
Replace
function update_row(){
var SQL = new gSQL();
SQL.DB('*redacted*').TABLE('DAILY-DATA').UPDATE('Pro').WHERE('ID', '=', '1').VALUES('KAOS').setVal();
}
by
function update_row(input = '1'){
var SQL = new gSQL();
SQL.DB('*redacted*')
.TABLE('DAILY-DATA')
.UPDATE('Pro')
.WHERE('ID', '=', input)
.VALUES('KAOS')
.setVal();
}
Main changes
added a parameter with a default value
Replaced a literal by the parameter
NOTES: The breaklines are not really required, it's a matter of programming style.
Add the below simple trigger to a .gs file in your Google Apps Script project.
function doGet(e){
const html = `
<input type="number" />
<button onClick="myFunction();">Submit</button>
<script>
function myFunction(){
google.script.run
.withSuccessHandler(()=> {
const div = document.createElement('div');
div.innerText = 'Done!'
document
.body
.appendChild(div)
})
.update_row(document.querySelector('input').value);
}
</script>`
return HtmlService.createHtmlOutput(html);
}
To test this you will have to deploy as web app. Please follow the instructions for this on https://developers.google.com/apps-script/guides/web.
Resources
https://developers.google.com/apps-script/guides/web
https://developers.google.com/apps-script/guides/html/communication?hl=en#forms
I'm trying to make a simple JS function that takes a few of my sites and send the user to a random site once the script activates. I'm using it in two locations one of them is in the navigation php which I include on all sites, and the other is on a hottest.php site.
const rng = new Array();
rng[0] = "http://localhost/joker.php";
rng[1] = "http://localhost/loophero.php";
rng[2] = "http://localhost/godofwar.php";
rng[3] = "http://localhost/friends.php";
function randomlink(){
window.location=randomlinks[Math.floor(Math.random()*randomlinks.length)]
}
I've tried adding onload to the body of a site to test however it does not send to another site once clicked. Don't know it means much but I'm testing my php site on mamp local server.
I use the randomlink in 2 situations on for testing peropuses but neither of them work those are
<li class="nav-item">
<a class="nav-link" href="hottest.php" onclick="randomlink();"><i class="fas fa-fire"></i></a>
</li>
and
<head>
<title>DIGIME</title>
<?php require $meta;?>
<?php require $css;?>
<?php require $bootstrapCss; ?>
<?php require $script; ?>
</head>
<body onload="randomlink();">
<?php require $navigation ?>
The solutions I've found online seem to work for others however they do nothing for me, could this be related to my sites being .php? (Note that other js functions I have work on the sites).
Easy, you are using randomLinks in your function, and its undefined.
You have 2 ways to fix your code
Method 1: Add a parameter to your function
const rng = new Array();
rng[0] = "http://localhost/joker.php";
rng[1] = "http://localhost/loophero.php";
rng[2] = "http://localhost/godofwar.php";
rng[3] = "http://localhost/friends.php";
function randomlink(randomlinks){
window.location.href = randomlinks[Math.floor(Math.random()*randomlinks.length)];
}
And then you can call your function using rng as a parameter: randomlink(rng)
Method 2: Define the links inside the function:
function randomlink(){
const rng = new Array();
rng[0] = "http://localhost/joker.php";
rng[1] = "http://localhost/loophero.php";
rng[2] = "http://localhost/godofwar.php";
rng[3] = "http://localhost/friends.php";
window.location.href = rng[Math.floor(Math.random()*rng.length)];
}
And then you can call your function without using any parameter: randomlink()
I use CreateTemplateFromFile and push a variable inside my template. My template file is including another file, but I'm not able to push this variable in the second file embedded.
Here below what I've tried:
index.html:
<!DOCTYPE html>
<html>
<?!= include('header'); ?>
<?!= include('style'); ?>
<body>
...
</body>
<?!= include('script'); ?>
</html>
the script part of the index.html in a separate file:
<script>
function getData() {
$("#loadingMessage").html('Loading');
console.log('myContent:', <?= data ?>);
...
}
</script>
The doGet part of the Google apps script code:
var template = HtmlService.createTemplateFromFile('index');
template.data = myContent;
return template.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
the variable is correctly pushed in index.html but not reach the script part.
Any idea ? Maybe to include the script file as a template also ?
How to pass variables between Apps Script and Javascript.
Google Apps Script features the method google.script.run that can be called from the JS part of a Web App. The methods allows to pass parameters to an Apps Script function and to assign the return value of the GAS function back to a JS function.
Sample:
.gs file
function doGet() {
var template = HtmlService.createTemplateFromFile('index');
return template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function myContent(input) {
var myContent="foo"+input;
return myContent;
}
HTML/js file
<html>
<head>
<base target="_top">
</head>
<body onload="getData()">
<script>
function getData() {
google.script.run.withSuccessHandler(proceedData).myContent("bar");
...
}
function proccedData(returnValue) {
var data = returnValue;
}
</script>
</body>
</html>
If you want to use scriptlets
The documentation specifies:
Remember, however, that because template code executes before the page is served to the user, these techniques can only feed initial content to a page. To access Apps Script data from a page interactively, use the google.script.run API instead.
Because scriptlet code executes before the page is served, it can only run once per page; unlike client-side JavaScript or Apps Script functions that you call through google.script.run, scriptlets can't execute again after the page loads.^
scriptlets can call functions defined in other code files, reference global variables, or use any of the Apps Script APIs.
In your case, if you want to use scriptlets, you either have to call a function or make your variable dataglobal, e.g.:
//global variable
var data=myContent;
function doGet() {
var temp=HtmlService.createTemplateFromFile("index.html");
return temp.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
Also keep in mind:
Templates can be challenging to debug because the code you write is not executed directly; instead, the server transforms your template into code, then executes that resulting code.
I'm looking for a way to list all files in specific google drive folder, also which updates the list automatically, and let everyone possible to look. I've found quite amount of articles that creates a spreadsheet to list them but they don't update themselves. I just can understand bit of JavaScript of I tried to modify some of other codes to no avail. Here is what I've done.
I created a Google Apps Script file
function doGet(e){
return HtmlService.createHtmlOutputFromFile('list.html');}
and inside list.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var dir = "SpinFest2016 KPDS Clips"
function listFilesInFolder(dir) {
var folder = DriveApp.getFoldersByName(dir).next();
var contents = folder.getFiles();
var file;
var name = [];
var date = [];
var desc = [];
for (var i = 0; i < contents.length; i++) {
file = contents[i];
name[i] = file.getName();
date[i] = file.getDateCreated();
desc[i] = file.getDescription();
};
};
</script>
</head>
<table style ="width: 100%">
<tr>
<th>이름</th>
<th>제출일</th>
<th>비고</th>
<tr>
<td><p id="name"></p></td>
<td><p id="date"></p></td>
<td><p id="desc"></p></td>
</tr>
<script type="text/javascript">
document.getElementById("name").innerHTML = name;
</script>
</table>
</body>
</html>
I tried to list only file names first but it never worked, and I can't figure out what's wrong. If you can point me which part is wrong and what I have to do, I'd very appreciate you're help. If there's any other better way (not only google-apps-script but also other ways to display file list) that fits conditions below I'd very thankful.
lists file names in google drive
anyone with link can view the list
list updates automatically (whether periodically or on any change occurs)
getFiles() will return a FileIterator, it may not have a .length property. Change the loop into a while-loop and check if the iterator hasNext is true, this way it will iterate. Also, try to change how you push items in to the array. See the modified snippet, hopefully this works.
while (contents.hasNext()){
file = contents.next();
name.push(file.getName());
date.push(file.getDateCreated());
desc.push(file.getDescription());
};
What goes after this, how you display it will be up to you.
As written, your doGet gives a web browser an HTML page with some JS code embedded in it, which the browser will try to execute. And fail, since a web browser has no idea about DriveApp; it can run JavaScript, not Apps Script.
It's possible to execute Apps Script code in scriplets embedded in a page served by doGet, but the syntax make take a while to get used to.
For a simple page like yours, I would just create all HTML within doGet function, and serve that. See my example.
There was one more issue with your code: folder.getFiles() returns a file iterator, not an array. This is something you loop over using hasNext and next methods, as shown below.
function doGet(e) {
var template = '<table style ="width: 100%"><tr><th>name</th><th>Date</th><th>Description</th></tr>APPS_SCRIPT_CONTENT</table>';
var dir = 'SpinFest2016 KPDS Clips';
var folder = DriveApp.getFoldersByName(dir).next();
var contents = folder.getFiles();
var file, name, date, desc, list = [];
while (contents.hasNext()) {
file = contents.next();
name = file.getName();
date = file.getDateCreated();
desc = file.getDescription();
list.push('<tr><td>' + name + '</td><td>' + date + '</td><td>' + desc + '</td></tr>');
}
var output = HtmlService.createHtmlOutput(template.replace('APPS_SCRIPT_CONTENT', list.join('')));
return output.setTitle('Directory List').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
This will serve up a static HTML file with the current snapshot of the directory. If the user reloads, they will get a possibly fresher copy. The file will not update on its own if the directory contents are changed; I don't think this even possible on this platform. With a scriplet running Apps Script code, one could try to update periodically, but this seems hardly practical: why waste your Apps Script execution time quota on users who opened your webpage and went for a walk?
I have a page that only contains a string and need to read it from a page in a different domain. I have tried to do it via a dynamic script hack (to avoid the security restrictions) and can read that string but cant bring it in a callback to keep working with it in a variable.
My problem is that I need to do it only using javascript.
Here is the code that I am currently using:
index.html:
<html>
<head>
<script type="text/javascript">
function xss_ajax(url) {
var script_id = null;
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', url);
script.setAttribute('id', 'script_id');
script_id = document.getElementById('script_id');
if(script_id){
document.getElementsByTagName('head')[0].removeChild(script_id);
}
document.getElementsByTagName('head')[0].appendChild(script);
}
var url = "http://otherdomain.com/ping.html";
xss_ajax(url);
</script>
</head>
<body>
</body>
</html>
ping.html:
1|1739
Very much thanks and sorry my english.
Your result from ping.html dose not have any variables defined, if you say
made an object like
result = [1,1739];
and in index.html you declared
var result = [];
then you could work with that.