Compiled template reference is undefined when calling dust.loadSource() in browser - javascript

I'm trying to render HTML using compiled templates with dust.js in a browser (not server-side with node.js). If I compile the template in the client-side javascript, it works fine. If I pre-compile the template and include it as a script tag as recommended, the dust.loadSource statement results in the Chrome debugger saying: "Uncaught ReferenceError: nowork is not defined", where "nowork" is the template name. So...
This HTML and script works:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>This Works</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="dust-full-0.3.0.min.js"></script>
</head>
<body>
<div id="bingo"></div>
<script type="text/javascript">
var templateKey = 'works';
var myView = {"people":[{"name":"Fred"},{"name":"Harry"},{"name":"Linda"},{"name":"Mary"}]};
dust.loadSource(dust.compile("{#people}<br/>{name}{/people}", templateKey));
dust.render(templateKey, myView, function(err, out) {
$('#bingo').html(out);
});
</script>
</body>
</html>
But this doesn't:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>This Doesn't Work</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="dust-full-0.3.0.min.js"></script>
<script type='text/javascript' src="nowork.js"></script>
</head>
<body>
<div id="bingo"></div>
<script type="text/javascript">
var templateKey = 'nowork';
var myView = {"people":[{"name":"Fred"},{"name":"Harry"},{"name":"Linda"},{"name":"Mary"}]};
dust.loadSource(templateKey);
dust.render(templateKey, myView, function(err, out) {
$('#bingo').html(out);
});
</script>
</body>
</html>
Where the included nowork.js file contains:
(function() {
dust.register("nowork", body_0);
function body_0(chk, ctx) {
return chk.section(ctx.get("people"), ctx, {
"block": body_1
}, null);
}
function body_1(chk, ctx) {
return chk.write("<br/>").reference(ctx.get("name"), ctx, "h");
}
return body_0;
})();
Can anyone help?
I just realized, that this may be due to these files not being served on a machine with node.js installed. I'm actually working locally on my desktop machine. Is that it?

You actually don't need to call dust.loadSource when you are serving pre-compiled templates. Internally, dust.loadSource just does an eval on the string of JavaScript that is returned by dust.compile. If you remove the dust.loadSource line, your template should render properly.
Node.js isn't necessary for what you are attempting here. As a matter of fact, dust-full isn't necessary, either. You can use dust-core if all you are doing is rendering on the client.

Related

Injecting data into HTML tag

I'm developing an extension for Microsoft Edge and have learned from the docs here https://learn.microsoft.com/en-us/microsoft-edge/extensions/guides/creating-an-extension#writing-a-more-complex-extension that I can use Javascript for data manipulation.
For some reason though, when I try to modify a DOM element like this:
<!DOCTYPE html>
<html>
<body>
<p></p>
<script type='text/javascript'>
document.getElementsByTagName('P')[0].innerHTML = 'something';
</script>
</body>
</html>
I get the desired result in any HTML / JAVASCRIPT interpreter but when I try to test it out in the extension the DOM manipulation isn't working. The p element isn't populated with 'something'. The manifest.json file is included in the extension folder I'm just not including it here as it's not relevant to the question.
How should I go about this ?
Update:
window.html:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<link rel='stylesheet' href='window.css'>
</head>
<body>
<div><p></p></div>
<script src="window.js"></script>
</body>
</html>
window.js:
window.onload() {
document.getElementsByTagName('P')[0].innerHTML = 'hakuna matata';
};
You should import the JavaScript function using <script> tag like below:
In myfunction.js file of js folder:
document.getElementsByTagName('p')[0].innerHTML = 'something';
In html file:
<!DOCTYPE html>
<html>
<body>
<p></p>
<script src="js/myfunction.js"></script>
</body>
</html>
I tested it in Edge extension: If we use the JavaScript function directly in the html page then it doesn't work. If we use a link to the js file then it works.

Why is the browser trying to load a local JavaScript file from a server?

I have a simple HTML page that is attempting to access both remote and local JavaScript files:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script src="https://js.arcgis.com/3.19/"></script>
<script src="SearchExtent.js"></script>
<script>
require([
...
SearchExtent.js is stored in the same folder as the HTML page.
When debugging the HTML page both in Chrome and Edge, a 404 error occurs indicating that the following resource can't be found:
https://js.arcgis.com/3.19/SearchExtent.js
Why is the browser looking on the remote service instead of the local filesystem>
Dojo must be configured correctly to use both local and CDN sources. Following is the code that correctly loads content from both the CDN and the local server:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<link rel="stylesheet" href="https://js.arcgis.com/3.19/esri/css/esri.css">
<script>
var dojoConfig = {
paths: { js: location.pathname.replace(/\/[^/]+$/, "") + "/js" }
};
</script>
<script src="https://js.arcgis.com/3.19"></script>
<script>
require([
"js/SearchExtent",
"dojo/domReady!"
], function (SearchExtent) {
console.log("...");
});
</script>
</head>
<body>
</body>
</html>
The paths property of dojoConfig is used to specify the location of the "js" alias on the local server. Also note that there is not an explicit reference to the custom JavaScript module. The call to require references the custom module using the alias defined in the paths property.

How to apply GString interpolation in a js file in Grails

My GSP file (in Grails 3.1.10):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<asset:javascript src="jquery-2.2.0.min.js"/>
<asset:javascript src="myfile.js"/>
</head>
<body>
<span id="greeting"></span>
</body>
</html>
myfile.js:
greeting = "${resp}"; // resp is passed from controller
$(document).ready(function(){
$('#greeting').val(greeting);
});
Well, I believe in that every grails developer knows if I move myfile.js into my GSP file, it will work.
However, I hope to know how to let the standalone js file can handle the inline variable of GString correctly.
Thanks.
Below is the approach I followed when ran into same problem like yours.
Pass your GString variable to external JS by following way.
Add the below function in your external JS
function view_handler_function(greetingValue){
//assign the value to your element
$('#greeting').val(greetingValue);
.....
//Your other handling code
}
Call your function from your view
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<asset:javascript src="jquery-2.2.0.min.js"/>
<asset:javascript src="myfile.js"/>
</head>
<body>
<span id="greeting"></span>
<script>
var greeting = "${resp}"; // resp is passed from controller
$(document).ready(function(){
//call to your external function
view_handler_function(greeting);
});
</script>
</body>
</html>
Note: This may or may not be the exact answer you are looking for but just one way around I follow.
this is out of the box simply not possible, and it's not a good idea either (although of course you could use a controller action as javascript src and in that action read in the js file and run it's content through a e.g. simpleTemplateEngine)
having js files be interpreted like gstrings/other templates would mean that any caching (bundle files via asset pipeline, cdn distribution and browser caching) had to be disabled.
however, you can simply serve the js files statically and e.g. provide your dynamic input as global variables in inline javascript (e.g. from your layout):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<span id="greeting"></span>
<g:javascript>
var greeting = "${resp}";
</g:javascript>
<asset:javascript src="jquery-2.2.0.min.js"/>
<asset:javascript src="myfile.js"/>
</body>
</html>

Does loading scripts dynamically block the rendering?

I'm trying to load bootstrap.min.js file.
I have two options.
The first one is to load it from a remote server:
<!DOCTYPE html>
<html lang='ru'>
<head>
<meta charset='utf-8'>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
</head>
<body>
...
</body>
</html>
The second one is to load it from my server:
<!DOCTYPE html>
<html lang='ru'>
<head>
<meta charset='utf-8'>
<script src="js/bootstrap.min.js"></script>
</head>
<body>
...
</body>
</html>
In the first case the script will load asynchronously which means the rendering of my page won't be blocked.
In the second case the script will block the rendering of my page. Am I correct?
How will blootstrap.min.js be loaded (async or sync) if I try to do this :
<!DOCTYPE html>
<html lang='ru'>
<head>
</head>
<body>
<script>
var bootstrap = document.createElement('script');
bootstrap.src = "http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js";
var head = document.getElementsByTagName('head')[0];
head.appendChild(bootstrap);
</script>
...
</body>
</html>
And this:
<!DOCTYPE html>
<html lang='ru'>
<head>
</head>
<body>
<script>
var bootstrap = document.createElement('script');
bootstrap.src = "js/bootstrap.min.js";
var head = document.getElementsByTagName('head')[0];
head.appendChild(bootstrap);
</script>
...
</body>
</html>
I have a hunch that in both cases the rendering won't be blocked. What do you think? Thanks!
If you put the source-loading code at the end of your <body> tag, the rendering won't be blocked, even though the new script tags are appended to the head. That's because most of the rendering is already done when you get to that part.
In newer browsers, you can add an async attribute to the script tag, which will not block rendering. So I suspect loading the file asynchronously via JS will not block rendering either, even if you do it near the top of the file.

Why is body onload not working in chrome

I'm encountering a problem where my body onload="constructor()" is not being run. It works fine for me in firefox but I don't understand why it's not working for me in chrome. Here's the code I'm working with, I made a separate file and deleted everything to the bare minium to try figure out what was going wrong:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Personality Font</title>
<link rel="stylesheet" type="text/css" href="p1.css" />
<script type="text/javascript" src="data.js"></script>
<script type="text/javascript">
//<![CDATA[
function constructor(which)
{
console.log("IN CONSTRUCTOR"); //In Constructor
var text = document.createElement('p');
text.appendChild(document.createTextNode("BLAH"));
document.getElementsByTagName('body')[0].appendChild(text);
}
//]]>
</script>
</head>
<body onload = "constructor();">
<h1>Personal Fonts: Find the Typeface that Matches Your Personality</h1>
<form>
</form>
</body>
</html>
Chrome has a built-in function with the name constructor. Call the function something else.

Categories