I am a web guy doing mostly Perl server-side stuff, and I'm slowly coming to a few conclusions.
It is far better to do most of your code via Javascript and toss data back and forth via AJAX than it is to hit submit and reload a mostly-identical page
I like jQuery because I like CSS, and it's fun to chain together big long and scary-to-others definitions
There's something to that templating stuff.
You want your HTML elements to look like your HTML elements, and it's easier to define that in HTML:
<div class="sidebar_elem">
TEXT
</div>
Than it is to cobble up the same in Javascript or jQuery:
( '<div/>' )
.attr('id' , 'sidebar_elem' + i )
.addclass( 'sidebar_elem' )
;
( '<a/>' )
.attr('href' , link_url )
.appendTo( '#sidebar_elem' + i )
;
This is to say that I am no longer a templating agnostic, but I don't know which templating tool to believe in. I have looked into some jQuery-based templating plugins, but I have yet to become happy with any of them, in part because the ones I've seen seem to want to put all that code into the page itself, which breaks the "Only markup goes into HTML files, only style goes into CSS files, only code goes into JS files" mantra I keep reciting.
So, I'm looking for a Javascript-based templating tool that would allow me to have my templates in an outside file so I can have one template change cover a series of web pages. If it's jQuery-based, that's great, less stuff I have to learn, but it isn't a deal-breaker.
There are several good ones out there:
Mustache.js
Pure.js
Json Template
If you want a jQuery version, Tempest looks good.
The 2 libs I know that do not mix template coding with HTML markups are chain.js and PURE
chain makes only DOM manipulations.
PURE uses a mix of DOM and innerHTML as the DOM alone can be slow to render bigger templates.
I'm the main contributor of PURE, and we created it to build a web app on the ajax model you describe.
Take a look at this one http://ejohn.org/blog/javascript-micro-templating/. Made by John Resig, creator of jQuery, this one doesn't even need jQuery, and it's freaking small. It also stores templates in script tag (Daniel's answer). Example template:
<script type="text/html" id="user_tmpl">
<% for ( var i = 0; i < users.length; i++ ) { %>
<li><%=users[i].name%></li>
<% } %>
</script>
Maybe you can load them using src attribute if you really need them to be in separate files, which I don't think is a wise idea, because it means additional roundtrip to the server. So at the end, for the sake of optimization, you can store them in separate files, but embed them server side in the page that needs them.
Since there is no well defined API and a best library for templating, I would suggest you choose one that is actively developed. Below, I briefly explained two libraries that are actively being developed.
jQuery team decided that jQuery Templates will no longer be actively developed or maintained, thus I would strongly suggest NOT using it. See this blog entry.
You can use JsRender in accordance with JsViews to take full functionality provided by jQuery Templates and even more like data linking. You can find demos for JsRender and JsViews. I would suggest using these libraries since they are actively being developed by jQuery UI team but be aware that they are still not even beta!
Mustache is another templating solution that is actively being developed and it simplifies templates by combining conditional tags and enumeration tags. It also provides strong features like inverted sections, partials and high order sections with simple syntax. Mustache is also one of the fastest templating solutions See blog by Brian Landau. I, personally, find mustache a good templating solution since it has a simple syntax and performs well.
How about EJS?
Example from their page:
"EJS combines data and a template to produce HTML."
Data:
{title: 'Cleaning Supplies', supplies: ['mop', 'broom', 'duster'] }
Template:
<ul>
<% for(var i=0; i<supplies.length; i++) {%>
<li><%= supplies[i] %></li>
<% } %>
</ul>
Result:
mop
broom
duster
You should check out google closure template. It's completely independent so you can use it with any lib you want. It's a templating tool written in java.
http://code.google.com/closure/templates/docs/helloworld_js.html
It allows you to create a template on the server, run a java "compiler" on it and the output is a javascript function that takes json as its parameter.
{namespace examples}
/**
* Greets a person using "Hello" by default.
* #param name The name of the person.
* #param? greetingWord Optional greeting word to use instead of "Hello".
*/
{template .helloName}
{if not $greetingWord}
Hello {$name}!
{else}
{$greetingWord} {$name}!
{/if}
{/template}
This will generate a function called examples.helloName that can be called like
Their format is very IDE friendly, I get all the HTML syntax highlighting when editing the templates
examples.helloName({name: 'Ana', greetingWord:"Howdy"});
You can call other templates from within templates, it automatically html escapes your data (unless you tell it not to), provides bidirection support.
Another great thing is the fact that the templating tool can also generate java code. So somebody writing an app that must support browsers with scripting disabled can generate the HTML on the server if necessary.
Last but not least, unlike other js templating systems (), the template is parsed on the server, so the client side only has to do the merging of the template and data, the parsing of the template is done as a build step on the server.
http://dev.sencha.com/deploy/dev/docs/?class=Ext.XTemplate is an example of a templating tool that runs completely on the client. There are two problems with this approach, the parsing of the template is done on the client and your html has to be embedded in a javascript string. However, some IDEs (Intellij) will highlight the HTML inside JS strings).
What about JAML Code?
http://github.com/edspencer/jaml
Similar to a few of the above but I believe is a bit more logical...
It is the concept of defining your templates via JSON / JavaScript and then using a function in JavaScript to pass arguments to your template which gets it rendered and returned as an element.
There are implementations around for the various JavaScript Frameworks that exist.
Try out this:
https://www.npmjs.com/package/jlate
use CDN:
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
I given below working example where you can replace github template url with your own template sample:
https://raw.githubusercontent.com/webphonix/JLate/main/test_project/template/weblate_loop.html
<div class="row">
<% _.each(names, function(n){ %>
<div class="col-md-6"><%- n.name %></div>
<% }) %>
</div>
var author = [{
name: "Guru"
},
{
name: "Gurudev"
},
{
name: "Test"
},
{
name: "Webphonix"
},
];
$$("#my_temp").jlate({
names: author
});
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
<div>
<jlate id="my_temp" src="https://raw.githubusercontent.com/webphonix/JLate/main/test_project/template/weblate_loop.html" type="template">
Loading...
</jlate>
</div>
Try JLate:
https://www.npmjs.com/package/jlate
use version 0.0.2 instead 0.0.1
use below cdn:
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
Use a script block.
<script id="someId" type="text/html">
<!-- your template here -->
</script>
and one of many JQuery plugins.
http://weblogs.asp.net/scottgu/archive/2010/05/07/jquery-templates-and-data-linking-and-microsoft-contributing-to-jquery.aspx
I have a templating engine called stencil.js, which I believe is pretty sweet. It works with jQuery via the jquery-haml DOM building engine.
Write your template (which you can put in an external file and decode as JSON):
["%div.sidebar_elem"
["%a", { href: { key:'link' } },
{ key: "text" }
]
]
And run it through stencil along with your data:
$("#parent").stencil(template, { link: "http://example.com", text: "Click me!" });
There are more examples at the stencil.js GitHub project, but I think it's just what you're looking for.
It could use a couple more utility methods, and some code for an unfinished data binding component is still in the master branch, so drop me a comment if you’re interested and I'll see if I can clean it up.
check out ibdom, and some background/history here: Recommended JavaScript HTML template library for JQuery?
Could always go with jQuery-Templates: http://api.jquery.com/category/plugins/templates/
What about http://www.enfusion-framework.org
Stuff like this:
<span template>Our telephone number is {phone}.</span>
<span session>You are logged in as {nickname}.</span>
Related
I am trying to find the way to expand a JavaScript variable value in HTML.
I know that it is possible to do it in PHP, like this:
<?php
$myString = "Hello World";
?>
<p><?=$myString?></p>
Is it possible to do likewise in JavaScript with a similar native inline tag?
Note
I am aware of other solutions such as calling other functions, which is exactly what I want to avoid.
There is no native way for injecting JavaScript values into HTML by just using a tag like the PHP <=? tag. What comes closest might be ES6 template literals.
It can look like this:
var mystring = 'Hello World';
document.write(`
<p>${mystring}</p>
<div>
some other stuff
</div>
`);
This version of JavaScript is available in most browsers today, but will of course not work in older browser versions, nor for current Internet Explorer versions (are we surprised?) -- but it works in Edge.
There are no native capabilities in HTML that allow injection of JavaScript values following the PHP-like syntax. In my opinion, the above comes as close as you can get. The only way to access to JavaScript variables from within HTML is with specific attributes (like "onclick") -- which serve another purpose --, and with script tags, which do not work like the <?= PHP tag either, but more like the standard <?php tag.
Using templating libraries might be an option (e.g. mustache, underscore, EJS, handlerbars, pug, plates, dust.js, hogan.js, jsrender, markupjs, nunjucks...).
A simple, poor man's template library - class/content based
The above listed templating engines offer advanced features, but here is a very basic implementation that understands this kind of HTML:
<span class="template">`I want to say "${mystring}"`</span>
When the page loads, the "poor man's library" should render that as:
<span>I want to say "Hello World"</span>
Here is the code for doing just that:
/* my simple template library: you would include this from another JS file */
document.addEventListener("DOMContentLoaded", function(event) {
var templates = document.getElementsByClassName('template');
[].forEach.call(templates, function (template) {
template.textContent = eval(template.textContent);
template.setAttribute('class', '');
});
});
/* my set of variables */
var mystring = 'Hello World';
# my simple template CSS
.template {display: none};
<span class="template">`I want to say "${mystring}"`</span>
A simple, poor man's template library - attribute based
Here is variation on the same concept. Now the syntax is a custom tag inject of which the value attribute has the value to inject. Here it is the "library" that injects the template literal backticks. This could also have been done in the first version.
/* my simple template library: you would include this from another JS file */
document.addEventListener("DOMContentLoaded", function(event) {
var templates = document.getElementsByTagName('inject');
[].forEach.call(templates, function (template) {
template.textContent = eval('`' + template.getAttribute('value') + '`');
template.removeAttribute('value');
});
});
/* my set of variables */
var mystring = 'Hello World';
<inject value='I want to say "${mystring}"' />
I don't see how it's possible to achieve in JavaScript what you're trying to achieve.
The closest thing I can think of, is something like this :
<script>var message = "Hello World";</script>
<div>Before message</div>
<div>
<script>document.write(message);</script>
</div>
<div>After message</div>
It is, however, recommended to avoid using document.write!
Note
Based on the info you provided in the comments, I think you're looking for one of the following approaches :
Replace your Twig templates with Mustache templates, for which both an official PHP implementation and an official JavaScript implementation exist.
Use an (unofficial) port of Twig to JavaScript to process your Twig templates in JavaScript.
Using server side scripting it's as easy as pie to inject data in HTML like this (ASP.NET):
//Assuming theTime is a variable
<h1>the time is, #theTime</h1>
But in JavaScript one basically needs to:
Create an element:
<h1></h1>
Give it an ID:
<h1 id="whatever"></h1>
Create a script tag:
<script></script>
Locate the element by it's ID:
document.getElementById("whatever")
Then use innerHTML to modify it's content:
document.getElementById("whatever").innerHTML = "Hi, " + TheTIme;
Final code:
<h1 id="whatever"></h1>
<script>
document.getElementById("whatever").innerHTML = "Hi, " + TheTime;
</script>
Is it possible to inject values/data in JavaScript as one would do in ASP.NET / PHP?
EDIT: The variable is a JS variable and getting it from the server is under control.
Well you could use some template library like handlebars and use jquery to facilitate the element selection, example:
<div id="target"></div>
<script id="hi-template" type="text/x-handlebars-template">
Hi {{userName}}
</script>
<script type='text/javascript'>
var template = Handlebars.compile($("#hi-template").html());
$('#target').html(template({userName: "bob"}));
</script>
Javascript Templating solves exactly this problem of binding data to HTML elements.
Below are few of the common templating engines used these days:
Underscore.js
Handlebars.js
Mustache.js
If you are looking for something simple, try Micro Templating engine from John Resig
<h1>Hi, #theUsersName</h1>
I've never worked with ASP.NET, but I'm assuming #theUserName is a variable. If that's the case, then a 1 to 1 replacement for that is not possible. However, it's still possible.
I'm not sure how you're getting the username, but I would assume you have some way to get it into a JavaScript variable. In that case, I would suggest something like this:
function changeName(username) {
document.getElementById("username").innerHTML = username;
}
<h1>Hi, <span id="username">StackOverflow</span>!</h1>
<button onclick="changeName('user3088260')">Click to Change the Name</button>
Now, getting the data is a different story, I would assume an AJAX call, in which case you could do something like this
if(xmlhttp.responseText !== ""){
changeName("user3088260");
}
All that other stuff you mentioned in unnecessary.
I will also say the entire idea seems like a poor design choice. If you have a username, I would assume you have a login system. If you have a login system, then you have to validate the user before outputting the page. If you have to validate the user before outputting the page, then you have their username. If you have their username, then put it in the pre-rendered page. No need to use JS after you've outputted the page.
Hopefully that is what you're looking for. If not, I'm sure somebody else will be along shortly with something that does.
One of the easiest javascript template engines to get started with is Underscore. Here is a protected answer from SO explaining how to do it:
How to use underscore.js as a template engine?
As someone says, there are a lot of Javascript templating frameworks. Here you have a few of them:
Handlebars.js
mustache.js
Hogan.js
doT.js
nunjucks
jade
After picking one, you can (for example) do something like this:
<h1>Hi, {{userName}}</h1>
You can see an example of client-side templating working with Angular on this link.
In my application, I need to provide an API (something like the Google Maps javascript API), through which I can send some custom javascript (with some session and request related information) as the response. The javascript is then used to plot some graphs on the UI. I'm using Express with Jade as my templating engine. The code that I'm currently using is:
app.use('/graph',function(req, res){
//send out graph data
var var_name = req.session.var_name //fetch something from session
var graphData = fetchGraphData(req.query.graph); //function that fetches graph data
res.contentType("text/javascript");
res.render(__dirname + '/views/graph.jade', {
title: "Title", queryStr: JSON.stringify({var_name: var_name, graphData: graphData })
});
});
And the jade file:
| some_var_name = {
| initGraph : function(divId){
| //some code here
| var graphData = !{graphData}
| // do something
As a workaround, I have started each line of the jade file with |, so that jade parses the text as plain text, and doesn't add any html tags! It works fine, but is there a cleaner way to do this? The solution may or may not use Jade!
You should look into underscore templates. I think that for generating arbitrary text output it would be somewhat cleaner. Jade is purpose-built for rendering HTML.
You could also try Mustache or Handlebars.
Based on your comment, I see you'd like to keep using res.render for rendering the template. consolodate.js adds support for all major template engines to Express. Including Underscore templates, Handlebars, Mustache and Dust, mentioned by #TheHippo.
You may try to define JavaScript functions you need to send to the browser in a separate module, outside of the template, which is probably more correct way from the "concerns separation" point of view. Also if functions are defined in a separate module they can be used both in the server and in the browser.
Then you can convert the functions to strings using its toString() method either in a function that invokes the template or right inside the template, if it supports plain JavaScript which is the case with underscore, EJS and doT templates (I tried both underscore and EJS and ended up using doT which is not only the fastest but very versatile - check it out):
JS code:
// if you send the same functions you may want to convert them to strings in advance
var data = {
funcStr: func.toString();
};
res.render(view, data);
Template (doT):
<script type="text/javascript">
func = {{= it.funcStr }};
// now you can call it here if you want but I would use
// separate JavaScript files
func();
</script>
I use it to send pre-compliled templates to the browser together with the page on the first page load, but I think it can be used in your case too.
As a side question, why can't you just bundle all these functions in a separate JavaScript module and load them as normal script file?
You can use https://www.npmjs.com/package/rendercustomjs package, it works fine but in ejs templating
I need to include a JavaScript object (JSON) in my HTML page.
JSON is rendered at the same time page HTML is rendered on server. Data is not retrieved using AJAX call.
I can think of two ways of doing this, and looking for feedback and recommendations.
What are good practices for passing JavaScript (JSON) blob with a page?
Option 1
HTML:
<script type='text/javascript'>
var model = { <JSON> };
</script>
.js:
function doSomething() { <use this.model here> }
Option 2
HTML:
<script type='text/javascript'>
loadModel({<JSON>});
</script>
.js (included at the top of the html file):
var model = null;
function loadModel(model) { this.model = model; }
function doSomething() { <use this.model here> }
Variation
Instead of including JSON in HTML, JSON can be stored in a separate .js file. Any comments on doing so?
Option 1 lets you include .js file anywhere, and including it at the bottom of the page makes it render faster (good thing), but since JavaScript renders the model on the page, this makes it a moot point. Still not depending on the location of the .js inclusion makes it less error prone.
Also R# complains (reasonably) about model being uninitialized.
Option 2 feels better (it encapsulate details better, for one), but .js must be included before call to loadModel.
I have seen and done both ways, but didn't notice any significant advantages of one way over the other.
Server platform should be irrelevant, but it is IIS 7.5/ASP.NET MVC 3/Razor
Forget your two suggestions - both are extremely vulnerable to XSS. NEVER PUT UNTRUSTED TEXT IN A SCRIPT TAG.
Instead, use the owasp recommendation.
Stick your (HTML encoded) JSON in the DOM like so:
<div id="init_data" hidden>
<%= html_escape(data.to_json) %>
</div>
Then read it in JavaScript like so:
// external js file
var dataElement = document.getElementById('init_data');
// decode and parse the content of the div
var initData = JSON.parse(dataElement.textContent);
There would be ever so slightly more overhead with option two. As you have the overhead of a function call, and an extra variable (your parameter), which will be allocated and deallocated.
As you said, there is little advantage/disadvantage to either way.
Can you use jQuery? Then you can use the DOM ready event instead of including javascript in your HTML.
EDIT:
Hmm, in that case you could include the JSON inside a hidden element when the page is generated. Then inside the DOM ready event you could read and parse it from the page using jQuery.
Another alternative might be to use HTML 5 data attributes and including the data in one of those.
If it were me I'd probably just use an ajax call since it is easier and seems a little cleaner.
I'm building a Rails app that uses Pusher to use web sockets to push updates to directly to the client. In javascript:
channel.bind('tweet-create', function(tweet){ //when a tweet is created, execute the following code:
$('#timeline').append("<div class='tweet'><div class='tweeter'>"+tweet.username+"</div>"+tweet.status+"</div>");
});
This is nasty mixing of code and presentation. So the natural solution would be to use a javascript template. Perhaps eco or mustache:
//store this somewhere convenient, perhaps in the view folder:
tweet_view = "<div class='tweet'><div class='tweeter'>{{tweet.username}}</div>{{tweet.status}}</div>"
channel.bind('tweet-create', function(tweet){ //when a tweet is created, execute the following code:
$('#timeline').append(Mustache.to_html(tweet_view, tweet)); //much cleaner
});
This is good and all, except, I'm repeating myself. The mustache template is 99% identical to the ERB templates I already have written to render HTML from the server. The intended output/purpose of the mustache and ERB templates are 100% the same: to turn a tweet object into tweet html.
What is the best way to eliminate this repetition?
UPDATE: Even though I answered my own question, I really want to see other ideas/solutions from other people--hence the bounty!
imo the easiest way to do this would involve using AJAX to update the page when a new tweet is created. This would require creating two files, the first being a standard html.erb file and the second being a js.erb file. The html.erb will be the standard form which can iterate through and display all the tweets after they are pulled from the database. The js.erb file will be your simple javascript to append a new tweet upon creation, i.e.:
$('#timeline').append("<div class='tweet'><div class='tweeter'><%= tweet.username %></div><%= tweet.status %></div>")
In your form for the new tweet you would need to add:
:remote => true
which will enable AJAX. Then in the create action you need to add code like this:
def create
...Processing logic...
respond_to do |format|
format.html { redirect_to tweets_path }
format.js
end
end
In this instance, if you post a tweet with an AJAX enabled form, it would respond to the call by running whatever code is in create.js.erb (which would be the $('#timeline').append code from above). Otherwise it will redirect to wherever you want to send it (in this case 'Index' for tweets). This is imo the DRYest and clearest way to accomplish what you are trying to do.
Thus far, the best solution I found was Isotope.
It lets you write templates using Javascript which can be rendered by both the client and server.
I would render all tweets with Javascript. Instead of rendering the HTML on the server, set the initial data up as JS in the head of your page. When the page loads, render the Tweets with JS.
In your head:
%head
:javascript
window.existingTweets = [{'status' : 'my tweet', 'username' : 'glasner'}];
In a JS file:
$.fn.timeline = function() {
this.extend({
template: "<div class='tweet'><div class='tweeter'>{{tweet.username}}</div>{{tweet.status}}</div>",
push: function(hash){
// have to refer to timeline with global variable
var tweet = Mustache.to_html(timeline.template, hash)
timeline.append(tweet);
}
});
window.timeline = this;
channel.bind('tweet-create', this.push);
// I use Underscore, but you can loop through however you want
_.each(existingTweets,function(hash) {
timeline.push(hash);
});
return this
};
$(document).ready(function() {
$('#timeline').timeline();
});
I haven't tried this, but this just occurred to me as a possible solution:
In your view create a hidden div which contains an example template (I'm using HAML here for brevity):
#tweet-prototype{:style => "display:none"}
= render :partial => Tweet.prototype
Your tweet partial can render a tweet as you do now.
.tweet
.tweeter
= tweet.username
.status
= tweet.status
When creating a tweet prototype you set the fields you want to the js-template replacement syntax, you could definitely dry this up, but I'm including it here in full for example purposes.
# tweet.rb
def self.prototype
Tweet.new{:username => "${tweet.username}", :status => "${tweet.status}"}
end
On the client you'd do something like:
var template = new Template($('#tweet-prototype').html());
template.evaluate(.. your tweet json..);
The last part will be dependent on how you're doing your templating, but it'd be something like that.
As previously stated, I haven't tried this technique, and it's not going to let you do stuff like loops or conditional formatting directly in the template, but you can get around that with some creativity I'm sure.
This isn't that far off what you're looking to do using Isotope, and in a lot of ways is inferior, but it's definitely a simpler solution. Personally I like haml, and try to write as much of my mark up in that as possible, so this would be a better solution for me personally.
I hope this helps!
To be able to share the template between the javascript and rails with a mustache template there is smt_rails: https://github.com/railsware/smt_rails ("Shared mustache templates for rails 3") and also Poirot: https://github.com/olivernn/poirot.