I am using AppEngine with the webapp framework (python). In my script I am generating javascript code dynamically with Django, for example:
python controller file
template_values = {
'page': '1',
}
path = os.path.join(os.path.dirname(__file__), "../views/index.html")
self.response.out.write(template.render(path, template_values))
index.html file
<html>
<head>
...
<script>
{% if page %}
alert("test");
{% endif %}
</script>
</head>
<body>
...
</body>
</html>
Now, instead of using inline <script> tags I would like to use the <link> tags with a reference to a JS file containing the script. However, I can't quite understand I can do that using the templates engine. If I include a JS file (dynamically) it would somehow have to know the value of "page", but "page" is known in the scope of index.html only.
Any ideas?
Thanks,
Joel
If you want dynamically generate your javascript code in your html,
you can write the code inside python code
page = 0
template_values = {
'js_code': 'alert("test:'+str(page)+'")',
}
path = os.path.join(os.path.dirname(__file__), "../views/index.html")
self.response.out.write(template.render(path, template_values))
in index.html
<script>
{{js_code}}
</script>
If you want to generate a js file dynamically, you can try to pretend there is a js file,
and generate its content.
class JSHandler(BaseHandler):
def get(self):
page= str(self.request.get("page"))
js_code ='alert("page:'+page+'");'
self.response.out.write(js_code)
def main():
application = webapp.WSGIApplication([
('/code.js', JSHandler),
], debug=True)
wsgiref.handlers.CGIHandler().run(application)
Then you can write this code in your html
<script type="text/javascript" src="/code.js?page={{page}}">></script>
You are either over-complicating a simple situation, or you haven't explained your problem clearly.
If you want to include an externally-located JavaScript file, you would use a <script> tag, not <link>.
If you have template code like this:
<html>
<head>
{% if page %}
<script type="text/javascript" src="/js/foo.js"></script>
{% endif %}
</head>
...
</html>
and page is not None, the template will render the following HTML to the browser:
<html>
<head>
<script type="text/javascript" src="/js/foo.js"></script>
</head>
...
</html>
and the browser will try to load the resource pointed to by the <script> tag. The browser has no knowledge of how that tag got into the HTML that it loaded.
Related
I'm considering vue.js as a migration target for an AngularJS (1.x) webapp.
This app loads a lot of "widgets" in its main page
<script optimize-inline src="data/widgets/solargraph/solargraph.js"></script>
<script optimize-inline src="data/widgets/sensorgraph/sensorgraph.js"></script>
<script optimize-inline src="data/widgets/astralgraph/astralgraph.js"></script>
Each one of these widgets is a custom directive which defines a custom tag.
For example data/widgets/astralgraph/ contains the following files
data/widgets/astralgraph/astralgraph.css
data/widgets/astralgraph/astralgraph.html
data/widgets/astralgraph/astralgraph.js
and is instanced as <astralgraph class="stickies-container"></astralgraph> in the main page.
.css is pulled in by the .html file via the following line
<link optimize-inline
rel="stylesheet"
type="text/css"
href="data/widgets/astralgraph/astralgraph.css?reload_times={## when ##}">
and the .html file is pulled in via templateUrl: 'data/widgets/astralgraph/astralgraph.html' in the .js file.
This normally causes the browser to pull in each .js file, which then pull in the .html files and so on.
Now comes the important part.
There are these optimize-inline markers.
These are not used by JavaScript, but are used by the Python server to inline the widgets into the main page. This way only one file is returned and no widget files (no .js, no .html and no .css) need to be loaded by the browser, since they are all in the (now big) main page.
First the content of the .js files is loaded by the server, inserted into the main page into a <script>-tag, but before writing that <script>-tag the templateUrl line is parsed, the content of the .html file written into a <script type="text/ng-template">-tag, like <script type="text/ng-template" id="data/widgets/astralgraph/astralgraph.html">...HTML IS HERE...</script>
This is the way the webapp works, it may have its drawbacks vs using webpack or the like, but it has its benefits which I appreciate a lot.
Now I've been checking out the feasibility of moving over to vue.js, and using single file components (astralgraph.vue) together with httpVueLoader solves the issue of being able to create widgets and load them without requiring a build system like webpack.
Now I'm still missing the ability to inline these .vue files into one big main page. How can I archive this without resorting to webpack, but by using the with open('widgets/astralgraph.vue') as file: ... in the Python server? By this I don't mean how do I implement this in Python, but rather how do I have to structure the resulting page so that it is a valid vue.js app.
Like in AngularJS I have the transformation from
/main.html
<script src="widget/example1.js"/>
<script src="widget/example2.js"/>
/widget/example1.js
/widget/example1.html
/widget/example1.css
/widget/example2.js
/widget/example2.html
/widget/example2.css
to
/main.html
<!-- example1 -->
<style>content of example1.css</style>
<script type="text/ng-template" id="example1.html">content of example1.html</script>
<script>content of example1.js</script>
<!-- example2 -->
<style>content of example2.css</style>
<script type="text/ng-template" id="example2.html">content of example2.html</script>
<script>content of example2.js</script>
In vue.js it would be from
/main.html
components: {
'example1': httpVueLoader('widget/example1.vue'), // optimize-inline
'example2': httpVueLoader('widget/example1.vue') // optimize-inline
},
/widget/example1.vue
/widget/example2.vue
to
// this I don't know
As for the httpVueLoader('widget/...') lines, I would regex them out and adapt it accordingly. It also wouldn't be an issue to load the .vue file into an XML-parser like BeautifulSoup to modify the .vue file contents as necessary before writing it into the main page. They could have an // optimize-inline comment in order to tell the server which components should get inlined and which not. In essence it would be a very rudimentary bundler which bundles the files on each page fetch.
For those who wonder what this astralgraph widget looks like:
This is possible, but you'll lose the ability to use scoped css.
The normal, non-optimized setup will look like this:
app.html:
<html>
<head>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/http-vue-loader"></script>
</head>
<body>
<div id="my-app">
<my-component></my-component>
</div>
<script type="text/javascript">
new Vue({
el: '#my-app',
components: {
'my-component': httpVueLoader('my-component.vue')
}
});
</script>
</body>
</html>
my-component.vue:
<template>
<div class="hello">src: Hello {{who}}</div>
</template>
<style>
.hello {
background-color: #ffe;
}
</style>
<script>
module.exports = {
data: function() {
return {
who: 'world'
}
}
}
</script>
The optimize-inline'd file will then need to look like this:
app.html
<html>
<head>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<!--============== my-component begin ==============-->
<template id="my-component-template">
<div class="hello">src: Hello {{who}}</div>
</template>
<style>
.hello {
background-color: #ffe;
}
</style>
<script type="text/javascript">
Vue.component('my-component', {
template: '#my-component-template',
data: function() {
return {
who: 'world'
}
}
});
</script>
<!--============== my-component end ==============-->
<div id="my-app">
<my-component></my-component>
</div>
<script type="text/javascript">
new Vue({
el: '#my-app',
components: {
//'my-component': httpVueLoader('my-component.vue')
}
});
</script>
</body>
</html>
So basically the server needs to modify the content of the .vue file in the following way:
rename the <template> to <template id='my-component-template'>
replace module.exports = { with Vue.component('my-component',
{ template: '#my-component-template', and add a closing ); to the last line of the script.
Then insert this modified content into the app.html file and comment out the 'my-component': httpVueLoader('my-component.vue') line, optionally also removing the <script src="https://unpkg.com/http-vue-loader"></script> line.
Using React, Node, and Express, with a single Nunjucks page for a template, I'm trying to pass a jwt-csrf token from my express server to the Nunjucks page as a javascript variable to be used in the React front-end (which will create post requests with the token).
This is the code in the njk template:
<html lang="en">
<head>
{% include "partials/head.njk" %}
<title>{{appname}}</title>
</head>
<body>
<div id="app"/>
<script src="/bundle.js" type="text/javascript"></script>
</body>
</html>
I had the idea of adding an additional script tag with a global variable, something like like:
<script>window.token = {{token}}</script>
but the {{ and }} get interpreted as javascript rather than as a nunjucks variable. How do I use nunjucks inside of Javscript?
Also, please let me know if what I'm doing is super not-secure, heh.
Pretty new to Jekyll (for github), I'm looking if there is a way to force raw in YAML header.
I'm using this HTML layout (called snippets)
<!DOCTYPE html>
<html ng-app="MyApp">
<head>
...
</head>
{{content}}
</html>
I have a few HTML content which uses it this way:
---
layout: snippets
---
{% raw %}
<body>
....
</body>
{% endraw %}
Because they provide AngularJS code, I have to enclosed it in raw/endraw block.
Is there a way to set the file content as raw directly in the header, kinda:
---
layout: snippets
raw: true
---
<body>
....
</body>
How to use Html template instead of Jade in Angular Application.
layout.html:
<body>
{% block content %}{% endblock %}
<h1>Hello!! whats up from layout</h1>
</body>
index.html:
{% extends 'includes/layout.html' %}
{% block content %}
<section> <h1>hello</h1></section>
{% endblock %}
Server.js
app.set('views',__dirname + '/server/views');
app.engine('html', require('ejs').renderFile);
app.set('view engine','html');
app.get('*',function(req,res){
res.render('index');
});
But i am not getting output as expected, below is the snap of what i am getting in the browser.
{% extends 'includes/layout.html' %} {% block content %}
hello
{% endblock %}
I don't understand what i am missing.
Looks like you're not utilizing the proper view engine. See this article by Rod Dodson. The crucial line is:
app.set('view engine', 'ejs');
You have:
app.set('view engine','html');
This means express is simply rendering your EJS templates as raw HTML. Make sure Express understands which view engine you want to use, and you should be set.
I have a nice little working MEAN stack application, and i believe it can be a good base for you to set up express/node app with AngularJS HTML templates.
Even if your configured view engine in app.js(server.js or whatever name you call it) might be jade or EJS, Expressjs is quite flexible,you can still serve the HTML partials using AngualrJS routes.
So my base index.html looks something like this:
NOTE: there are ways to efficiently load JS files, but since it's a small To-Do App. so i am not going for it.
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MEAN To Do Application </title>
<link href="vendor/flat-ui/css/vendor/bootstrap.min.css" rel="stylesheet">
<link href="vendor/flat-ui/css/flat-ui.css" rel="stylesheet">
</head>
<body ng-controller="AppCtrl">
<div ng-include="'app/header.tpl.html'"></div>
<div ng-view class="container-fluid"></div>
<script src="vendor/flat-ui/js/vendor/jquery.min.js"></script>
<script src="vendor/flat-ui/js/vendor/html5shiv.js"></script>
<script src="vendor/flat-ui/js/vendor/respond.min.js"></script>
<script src="vendor/flat-ui/js/vendor/video.js"></script>
<script src="vendor/flat-ui/js/flat-ui.min.js"></script>
<script type="text/javascript" src="vendor/angular-full/angular.min.js"></script>
<script src="vendor/angular-full/angular-resource.min.js"></script>
<script src="vendor/angular-full/angular-route.min.js"></script>
<script src="/socket.io/socket.io.js"> </script>
<script src="common/socketservice.js"></script>
<script src="app/app.js"></script>
<script src="app/meetups/meetups.js"></script>
</body>
</html>
Then here comes by Angular routes config(refer):
angular.module('meetups',['ngResource'],['$routeProvider',function($routeProvider){
$routeProvider
.when('/',{
templateUrl: 'app/meetups/list.tpl.html',
controller: 'MeetupsController'
})
.when('/create',{
templateUrl : 'app/meetups/create.tpl.html',
controller: 'MeetupsController'
})
.when('/:id',{
templateUrl: 'app/meetups/details.tpl.html',
controller: 'MeetupsController'
})
.when('/:id/edit',{
templateUrl: 'app/meetups/edit.tpl.html',
controller: 'MeetupsController'
})
.otherwise({redirectTo: '/'})
;
}]);
I hope i answered your question.
This is a clientside solution. Just FYI.
You may set any other character for angular's interpolate symbol:
app.config(function ($interpolateProvider) {
$interpolateProvider.startSymbol('[[').endSymbol(']]');
});
(but it's may hurt - ide with angular support didn't recognize your symbol)
The best practice of binding - is use ngBind whenever it's possible (instead of {{ }} expresions):
<span ng-bind="myVal"></span>
It is preferable to use ngBind instead of {{ expression }} if a template is momentarily displayed by the browser in its raw state before Angular compiles it. Since ngBind is an element attribute, it makes the bindings invisible to the user while the page is loading.
(from docs)
instead of
<span>{{myVal}}</span>
I am new to ServiceStack and Angular. Apologies if this is verbose.
with reference to Html5 pushstate Urls on ServiceStack
I would like to be able to have my api service served up from the root. ie http://mydomain.com/
If a user browses the route, I would like to serve up a default html page that bootstraps my angular app.
In the the app itself if angular calls mydomain.com/customer/{id} json should be served but if this is browsed directly it should serve the default html page and keep the url but the route in the service method does not need to be called. as this will be resolved by angular which will call the customer service itself for a json result.
There are probably a few different ways to make this work, as long as you don't need to support html5mode urls. I have hope that I'll be able to leverage this code to eventually support html5mode, but at the moment, I've resigned myself to hash based URLs.
Given urls like: http://example.com/ or http://example.com/#/customer/{id}, here's how to bootstap an angularjs single page app on a self-hosted servicestack project from the root of the domain.
To enable the markdown razor engine, add this to your AppHost config (not absolutely necessary, but my preference over the default razor engine):
Plugins.Add(new RazorFormat());
Place a file, default.md, in the root of your project, and ensure it's properties are "content/copy when newer". Put whatever content you want in there. The important thing is to assign the template file. (If you're using the default razor engine, an equivalent default.cshtml file should also work, but I've never tried it. ) The template file is what will bootstrap your angularjs app. This is what I have in my default.md:
#template "Views\Shared\_Layout.shtml"
# This file only exists in order to trigger the load of the template file,
# which bootstraps the angular.js app
# The content of this file is not rendered by the template.
My _Layout.shtml file looks like this (omitting irrelevant details). Note ng-app in the html tag, and the ng-view div in the body. Also note that I don't include <!--#Body--> in the file. I'm not using server side templates for this project.
<!DOCTYPE html>
<html lang="en" ng-app="MyApp">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="Content/css/app-specific.css"/>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<!-- Navbar goes here -->
<div class="container">
<header id="header">
<!-- Header goes here -->
</header>
<div ng-view></div>
<hr>
<footer id="footer">
<!-- Footer goes here -->
</footer>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="/Scripts/app-specific/app.js?3ba152" type="text/javascript"></script>
<script src="/Scripts/app-specific/app-services.js?3ba152" type="text/javascript"></script>
<script src="/Scripts/app-specific/app-controllers.js?3ba152" type="text/javascript"></script>
</body>
</html>