I'm trying to use Nunjucks (client-side) as the templating component of my project. I'm using xampp, apache for the server.
The problem is that when i put "nunjucks code" inside the index.html, it doesn't compile it. If i put "{% include "sidebar.html" %}" it just renders that in the DOM.
I'm being able to use the render method AFTER the DOM is loaded, and in my templates, everything works.
index.html (DOESN'T WORK):
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Meta, title, CSS, favicons, etc. -->
...
<body>
...
{% include "sidebar.html" %} // This gets rendered literally
...
</body>
...
So, basically i want to know if it's possible to use nunjucks functionalities in the first page that is served by apache (in this case, index.html).
Thanks in advance.
Try it
// index.html
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src = "/js/vendors/nunjucks.min.js"></script>
<script>
window.addEventListener('load', function () {
nunjucks.render('index.njk', {some-data}, (err, html) => body.innerHTML = err && err.message || html);
});
</script>
<body>
<!-- Empty body -->
</body>
</html>
// index.njk
{% include "sidebar.njk" %}
...
I found a hacky workaround, where i "add another layer of htmls".
So, in index.html, i have this code:
$(document).ready( function() {
nunjucks.configure('./includes', { autoescape: true });
nunjucks.render('dashboard_main.html', {}, function(err, res) {
$("#main_content").html(res)
});
});
And then, dashboard_main.html can have nunjucks code.
Related
I'm working in a Node.js app and I'm having trouble with a specific html page. All the pages I've done to this point are simply html and css, but in this case I have a multistep page that runs a script to move through the steps (showing diferent forms). In my case it won't load this script so the page doesn't work at all. The get request looks like this:
router.get("/reservaAula", eToken, (req, res) => {
jwt.verify(req.token, keyDocente, (err, data) => {
if (err) {
res.sendStatus(404);
} else {
res.render("reservaAula.html");
}
});
});
And the page is (the important part):
<!DOCTYPE html>
<html lang="en" id = "html">
<head>
<title>Reserva de Aula</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="/js/script.js"></script>
<script src="js/reservarAula.js"></script>
</head>
<body>
...
I've placed the script in the public folder, just like I placed my css, but no matter what I try it won't work. In the rest of the pages loads the other scripts in js folder correctly (like reservarAula.js), but not with script.js.
CSS and JS should be in the static folder and in your sub-folder. It should then work.
Example file location
/static/css/stylesheet.css
How to refer to it
/css/stylesheet.css
(You can do the same with JS)
So I'm having trouble with deciding on where to place my javascript in my Flask app. I currently have my scripts on each of my templates, but was planning to put it in the static folder, however, values don't get assigned through the flask app. What I'm asking is how would I want to structure my app in terms of wanting to alter variables in my javascript. An example of how I'm currently changing variables is below in the HTML script.
File structure:
static/
css
templates/
example.html
app.py
main.py
Flask:
#app.route('/')
def index():
a = 10
return render_template("index.html", a=a)
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Example </title>
</head>
<body>
<!-- Javascript files -->
<!-- Contents -->
<script>
var a = {{ a }};
alert(a);
</script>
</body>
</html>
It kind of depends. I personally save javascript files like bootstrap.js and jquery.js in static/, but javascript files which need access to my routes and/or variables returned from python I often also store within the html template. You could bypass this by sending ajax requests to an api route, but that's not ideal either in a lot of cases, and add a lot of extra overhead.
Here is another way to dynamically render js, but still keep it in its own files.
test.py
from flask import Flask, render_template_string, render_template
app = Flask(__name__)
#app.route('/')
def hello_world():
js = render_js('static/test.js', a="wow")
return render_template('test.html', js=js)
def render_js(fname, **kwargs):
with open(fname) as fin:
script = fin.read()
rendered_script = render_template_string(script, **kwargs)
return rendered_script
static/test.js
var a = "{{ a }}";
alert(a);
templates/test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Example </title>
</head>
<body>
<h2>nice</h2>
<script>
{{js|safe}}
</script>
</body>
</html>
I don't prefer it over just rendering the js in the html directly, but it's a possibility.
It's always a good idea to keep your javascript files separated from html templates. However, sometimes you need to pass some data from python directly to javascript. The best approach at the moment, in my opinion, would be to pass the desired data as a JSON response from your FLASK app and catch that data using AJAX or Jquery, etc.
In case you want to just keep it simple, you should separate javascript code that somehow interacts with your python code from code that does not. The latter should be in a static folder, while dynamic code can be placed into special block.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Example </title>
</head>
<body>
<!-- Javascript files -->
<!-- Contents -->
{% block extra_js %}
<script>
var a = {{ a }};
alert(a);
</script>
{% endblock %}
</body>
</html>
Here you have a nice {% extra_js %} block inside the main template that will allow adding some javascript code in child templates easy enough.
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>
I'm working with libgdx 1.9.2 and gwt 2.6.1.
After the GWT-compilation of my java app, I get a JS script (html.nocache.js) that I can include in my html page, and visualisate in a web browser (inside a div, here it's "embed-html"). That part is working nicely.
Here's the code:
<!doctype html>
<html>
<head>
<title>my-gdx-game</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link href="styles.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="html/html.nocache.js"></script>
</head>
<body>
<div id="embed-html"></div>
</body>
</html>
My next goal is to use web components, and more precisely custom elements, to have a simple tag <my-app></my-app> in any web page to get my application.
my index.html:
<!doctype html>
<html>
<head>
<title>my-gdx-game</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script src="webcomponents.js/webcomponents.js"></script>
<link rel="import" href="component.html">
</head>
<body>
<my-app></my-app>
</body>
</html>
my component.html:
<template id="template">
<div id="embed-html"></div>
<link href="styles.css" rel="stylesheet" type="text/css">
</template>
<script>
var helloDoc = document._currentScript.ownerDocument;
var myApp = document.registerElement('my-app', {
prototype: Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var root = this.createShadowRoot();
var template = helloDoc.querySelector('#template');
var clone = document.importNode(template.content, true);
root.appendChild(clone);
}
}
})
});
</script>
<script type="text/javascript" src="html/html.nocache.js"></script>
But the JS script generated by GWT-compilation has some document.write(...) inside; so all that is included is my empty div, my style sheet correctly loaded, and warnings: "Warning: A call to document.write() from an asynchronously-loaded external script was ignored". Since it is generated, I don't think I can avoid using these document.write().
If I put the <script type="text/javascript" src="html/html.nocache.js"></script> in the head of index.html (where it was before I tried using webcomponents), the app is not added inside the div, as it should, but under (the div and style sheet are included as expected).
And if I put the script inside the template, nothing happens.
So I am wondering if there is a way to have a GWT application working with web components, or if I should search for another way to easily include my application into external websites.
(If you wonder the reasons why I want to do so, it's because I want clients to be able to add my app easily on their own website, with only an import and a tag, the same way I could import a YouTube video or a Google map.)
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.