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.
Related
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)
I have a php file containing the following line;
$num= "<script type='text/javascript' src='hn_includes/common.js'>boo();</script>";
and of course have a javascript file common.js which contains a function boo()
This is never called...
In an attempt to debug, I've placed a console.log("common.js loaded"); at the top of the common.js file and this tells me that it is indeed being loaded but the call to function boo() never seems to happen.
Additionally, if I simply change my line of code above to;
$num= "<script>boo();</script>";
and add boo() to top of the php file as below;
<script>
console.log ("I'm here");
function boo()
{
console.log("boo");
}
</script>
I get both the "I'm here" and also the "boo".
Any suggestions on where I'm going wrong would be greatly appreciated...
You are only declaring variable in the PHP file. To make it valid accessible in page you need to echo it. like
$num= "<script type='text/javascript' src='hn_includes/common.js'>boo();</script>";
echo html_entity_decode($num);
I am trying to parse an external JSON file, and then parse it in javascript but i am getting an uncaught reference error.
I first declare the .json file in my html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
<script type="text/javascript" src="OnebusinessDataFormat_yelp.json"></script>
<title>title</title>
</head>
<body>
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Dropdown</button>
<div id="myDropdown" class="dropdown-content">
<a onclick="name()">NAME</a>
<a onclick="address()">ADDRESS</a>
<a onclick="bh()">BUSINESS HOURS</a>
<a onclick="menu()">MENU</a>
<a onclick="saf()">SERVICES and FEATURES</a>
</div>
</div>
<div id="name">
<p id="rest_name"></p>
</div>
</body>
</html>
I then try to parse that file in my javascript code:
var jsonFile = JSON.parse(OnebusinessDataFormat_yelp.json);
function name(){
document.getElementById("rest_name").innerHTML = jsonFile.name;
}
but when i select name from the dropdown it does not populate the <p> element with the restaurant name.
You need to use the Fetch API in vanilla JS if you want to get the contents of a file:
var jsonFile;
fetch("JOnebusinessDataFormat_yelp.json")
.then(res => res.json())
.then(data => jsonFile = JSON.parse(data));
Please also note that this line:
<script type="text/javascript" src="OnebusinessDataFormat_yelp.json"></script>
Will not work because you can't have a JSON file inside a <script> tag - JSON is JavaScript Object Notation (a string), and is a way of storing JavaScript objects in a simpler way than objects. You can only have a .js file inside a <script> tag.
you can use this code to get the local json file in javascript.
use this url for more reference. $.getJSON Reference
$.getJSON("test.json", function(json) {
console.log(json); // this will show the info it in console
});
I will explain to you how it work, hope it will help you think.
There are 2 types of JavaScript, Server and Client.
If your JavaScript is running on Node.js (Server), all you nee is require().
const json = require(jsonFilePath);
require() will automatically parse the JSON (.json extension file) and generate JavaScript Object for you.
If your JavaScript is running in a Browser (Client), you can't open files from user file system. Just Imagine if Javascript can open any file it want from user file system. All of our data will be in Facebook data center Description 😂.
So for obvious security reasons, you will not be able (as browser app) to open any file you want from the user file system. But you will be able to open files provided by the user like <input type="file" /> or create by yourself in specific way, other people already answered it, you can choose any solution that make sense to your app.
Use this
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'OnebusinessDataFormat_yelp.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
The function above will create a new instance of a XMLHttpRequest and load asynchronously the contents of OnebusinessDataFormat_yelp.json. I have gone with asynchronous but you can change the argument to false if you want a synchronous load. Thankfully all modern browsers support the native JSON.parse method. Remember our anonymous callback? here's how you use it.
function init() {
loadJSON(function(response) {
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
});
}
For more details refer - https://codepen.io/KryptoniteDove/post/load-json-file-locally-using-pure-javascript
I have a page that uses an external javascript file. That file requires variables that are different in Dev, QA and production environments, causing me to need to maintain multiple copies of the same script file for each environment.
I'd prefer to maintain the values of these variables in web.config (perhaps appSettings section), and resolve these values at runtime, before streaming the .js file to the browser. Is there a way to do this?
asp.net Can I inject configuration settings into javascript?
Sample Java Script
<script language="javascript" type="text/javascript">
var Publicvalue = abc();
function abc() {
Publicvalue = <%=MyProperty%>
alert(Publicvalue);
return Publicvalue;
}
</script>
Sample HTML
<asp:Button ID="btn" runat="server" Text="efeded" OnClientClick="return abc();" OnClick="btn_Click" />
Sample Code Behind
public int MyProperty
{
get
{
return 1;
}
}
I am trying to load some JavaScript files inside another JavaScript file in the following case:
js/script1.js
var script_1_method = function () {
console.log("Hello Script 1");
}
js/init-script.js
console.log("Initiating Scripts...");
loadScriptMethod('js/script1.js');
script_1_method();
console.log("Hello Script 2");
index.html
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/init-script.js"></script>
</head>
<body>
</body>
</html>
The Console output should be
Initiating Scripts...
Hello Script 1
Hello Script 2
I have looked into many JavaScript loaders like curl.js, RequireJS, JSL almost all of them do an Asynchronous way of loading files requiring callbacks for my scenario.
Is there a library to load the scripts in a synchronous way as in the above case without requiring callbacks.
Please let me know if there are any JavaScript loader libraries which cater to the above case.
It's possible to load same-origin scripts using a synchronous XHR:
var scr = getViaSynchronousXHR('js/script1.js'),
el = document.createElement("script");
el.appendChild(document.createTextNode(scr));
document.documentElement.firstChild.appendChild(el);
script_1_method();
A script element without a source is parsed and executed synchronously, because there is no wait for the file to be downloaded/fetched from cache.
if all your scripts are on the same domain, you can run a synchronous ajax call to get the script, use eval to run it, and then continue
The thing you want to do is quite difficult. I had a lot of problems with synchronous AJAX requests to correctly load my javascript files dynamically.
Actually I implemented something that worked synchronously on my project which is the same as you want.
It is only possible if you have a server-side scripting engine (e.g. PHP) to generate your HTML page.
The idea is to parse the init-scripts.js on server side prior to include them into the html code.
Instead of writing echo <script type="text/javascript" src="js/init-script.js"></script> in my PHP script I write : JavascriptLoader::addJavascript('js/init-script.js');
JavascriptLoader is a PHP class which manages scripts to be loaded.
This addJavascript function parses the init-script.js and, each time it encounters a line which starts with "loadScriptMethod(",
it parses and uses the string between brackets (e.g loadScriptMethod('thisString')) as the scriptToLoad
and then calls recursively JavascriptLoader::addJavascript($scriptToLoad);
JavascriptLoader::addJavascript then do an echo '<script type="text/javascript" src="'.$scriptToLoad.'"></script>' to write
I cannot publish the JavascriptLoader code from my project, but here is a simplified example of PHP code:
class JavascriptLoader{
...
public static function addJavascript($filepath){
self::init(); //Init to write the javascript loadScriptMethod definition into HTML output
if (!self::isScriptAlreadyLoaded($filepath)){
self::parseFile($filepath);
echo '<script type="text/javascript" src="'.$urlScript.'"></script>',"\n";
self::ajouterScriptDejaCharge($chemin);
}
}
private static function parseFile($filepath){
if (file_exists($filepath)){
$lines = file($filepath, FILE_SKIP_EMPTY_LINES);
foreach($lines as $line){
$matches = array();
$test = preg_match ('/^loadScriptMethod\(\s*[\'\"](.+)[\'\"]\s*\)/' , $line , $matches);
if ($test > 0){
$scriptToLoad = $matches[1];
//On inclut le fichier
self::addJavascript($scriptToLoad);
}
}
}
else{
throw new Exception('javascript source file '.$filepath.' does not exist.');
}
This also stores the $scriptToLoad into an array to avoid loading twice the same script (functions isScriptAlreadyLoaded and addScriptToAlreadyLoadedList).