Get return value of `include` in jade template - node.js

What I basically try to accomplish is to re-use jade partials/templates when getting data through a socket connection. Non working example:
socket.on('company_created', function(company) {
var html = include _company;
$('#companies ul').append(html);
});
Normally I had to create a new li and set the content like so (which is working as expected):
$('#companies ul').append($('<li>').text(company.name));
This is okay for a simple list, but if I had complexer list and stuff, this could get messy pretty quick, plus I had to write plain HTML again, so I figured re-using my already existing jade templates with all their goodness would be awesome, but had not luck, yet.
Any clue?
PS: Please do not tell my to use Ember, Backbone, Derby, Meteor, Angular or whatsoever.
Thanks in advance!

You can compile your jade sources to JS with jade.compile. Then include these sources in the client-side javascript, include jade's runtime.min.js, and refer to your jade templates as to normal JS functions in your client-side code.
For example,
server.js
app.get('/templates/:template.js', function (req, res) {
var template = req.params.template;
response.end([
"window.templates = window.templates || {};",
"window.templates[\"" + template + "\"] = " + jade.compile(template + ".jade", { client: true; });
].join("\r\n"));
});
client.js
$(function() { $("#placeholder").html(window.templates["content"]({user: "Daniel" })); });
content.jade
h1: Hello #{user}!
index.jade
!!!
html
head
script(src='/lib/jquery/jquery.js')
script(src='/lib/jade/runtime.min.js')
script(src='/templates/content.js')
script(src='/scripts/client.js')
body
#placeholder
Note that the code above might be syntactically incorrect and is provided solely to illustrate the idea.

we have a build step that compiles them to functions sort of like penartur mentioned. I dont use extend or include (which dont work on the client anyway ATM), but personally I find we have absolutely no need for that on the client at all since the DOM provides all the separation we need.

Related

Do I only have to use a templating language with express render?

I am learning node and express from the simplest and when rendering views using res.render('view',{data:data}) is it only a template engine like jade that fits in view. can I not use a normal html?
You can, but this is a problem I ran into when I was learning Node. If you do not want to use a templating engine, you can still have Node just spit out the contents of your HTML file in a static way. For example (VERY BASIC EXAMLE):
var base = '/path/to/your/public_html',
fs = require('fs'),
http = require('http'),
sys = requrie('sys');
http.createServer(function (req,res) {
path = base + req.url;
console.log(path);
path.exists(path, function(exists) {
if(!exists) {
res.writeHead(404);
res.write('Bad request: 404\n');
res.end();
} else {
res.setHeader('Content-Type','text/html');
res.statusCode = 200;
var file = fs.createReadStream(path);
file.on("open",function() {
file.pipe(res);
});
file.on("error",function(err) {
console.log(err);
});
}
});
}).listen(80);
console.log('server on tcp/80');
The great thing about Node is that it forces you to separate templates from logic (to a certain level, you can squeeze a lot of logic into template anyway).
I didn't like Jade and used EJS until it turned out that client-side EJS is different from server-side and you cannot really re-use templates in the browser (as you would definitely want at some point, when you start rendering pages in the browser). You can re-use simple EJS templates but you cannot re-use templates with partials (as most of your templates will be).
After a lot of searching and trial-and-error I ended up using doT templates that are very fast (the fastest there is, actually), light-weight (only 140 lines of JavaScript), can be easily integrated in Express (by following the pattern of consolidate - you can't use consolidate directly with doT yet), can be used in the browser (the function to load partials will have to be different, but it is easy again).
doT seems to have features that I haven't seen in other templating engines, has a very elegant syntax that is the closest to handlebars (my favourite) but still allows normal JavaScript inside (that's why I chose EJS in the first place).

Accessing jQuery object in JADE

During login, I save the userId in a jQuery cookie, so that I can access it by $.cookie('userId').
Now that I am trying to access it from Jade, as,
- if ($.cookie('userId') === userId)
I get an error
$ is not defined
How can I access the cookie ?
My code:
- if (($.cookie('userId')) === userId)
input(type='submit', value='Move')
else
input(type='submit', disabled, value='Move'')
You seem to misunderstand concepts. Let me give you a lecture. ;)
Basics. Cookie is stored on the client-side. So using jQuery $.cookie('userId') will retrieve it when this script is run on the client-side.
But here you use JADE templating engine on server-side. So you didn't even send the page to the client-side yet. So what cookie do you want to retrieve? There is no cookie, because you are at the server.
There's more. Running $.cookie('userId') throws the error, because you are on the server-side. There is no $ object. And there cannot be, because you cannot use jQuery on server-side (well, actually you can, but this is irrelevant at the moment). Did you define $ object in your route system? Or did you define helper $? I don't think so.
Express+JADE tutorial. Now let me give you a short tutorial. Say you have a view (in app.js)
app.get('/', function(req, res){
res.render('index.jade', { code: 500 });
});
Now in index.jade you can use code as a variable. So you can write your index.jade for example like this:
// some code
- if (code == 500)
input(type='submit', disabledm, value='Move')
- else
input(type='submit', value='Move')
// some code
and now it will work! You may also use JavaScript functions in template if you predefine them. For example (in your app.js)
app.helpers({
positive: function(no) { return no > 0; }
});
then in index.jade template you can use
- if (positive(-13))
input(type="submit")
and even combine these two concepts
- if (positive(code))
// do some stuff
To cookie or not to cookie. If you really need to use cookies (and you shouldn't except for sessions or CSRF for example) then you need to use client-side JavaScript. This means that you need to add (after jQuery)
script(src='my-path/my-script.js')
to the index.jade file and write my-script.js like this
$(document).ready(function() {
if ($.cookie('userId') == userId) {
// do something like append input to some holder
}
});
But there are several problems with that solution. First: what is userId (second part of equality)? You need to predefine it in your index.jade. For example using
script
var userId = #{ user.id };
and adding user object in your route. Second: cookies are local variables. Setting them requires additional server code which I do not thing you would like. This makes maintaining the app harder. And finally: storing a user's id in a cookie seems to be pointless. The final user don't even have to know it's own id. The server needs to know! Sessions system comes handy here.
Final note. The code you wrote shows us that you cannot distinguish between server-side and client-side JavaScript. The solution to your problem is to learn, learn and learn. Read tutorials and everything about JADE, Express and Node.js.
What #freakish said is right. You're trying server side vs. client side.
If the cookie is set you should be able to access it on server like so
app.use(express.cookieParser());
app.get('/', function(req, res){
// index is jade template
// local variable on jade template holds cookie value
// use req.cookies.userid
res.render('index', { userid: req.cookies.userid });
});

Mustache(-like) template engine for Express?

Is there a template engine for Express (node.js) which is based on Mustache or uses a similar syntax?
All I could find is haml, jade, ejs, jquery templates and one based on CoffeeScript (I write plain JS).
I want to write "normal" html, so only ejs and jqtpl would fit. I already use mustache with backbone so it would be best to also use it on the server side with Node.js
Just stumbled on this ancient thread but no one has mentioned consolidate.js, which seems to be the "right" way under Express 3 (refer to http://expressjs.com/faq.html). It also provides an easy way to switch/experiment with templating systems.
Here's a simple example - http://invitingthebell.com/2012/12/24/mustache-templates-in-express-3-0/.
Code, in case it disappears is:
var express = require('express')
, cons = require('consolidate')
, app = express();
// assign the mustache engine to .html files
app.engine('html', cons.mustache);
// set .html as the default extension
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
// test mustache
app.get('/', function(req, res){
var viewdata = { 'test' : 'Hey now.'};
res.render('index', viewdata);
});
app.listen(3000);
The index.html file in the views directory:
<html>
<head><title>Some CMS</title></head>
<body>
<h1>Mustache</h1>
<p>What do you say?</p>
<p>{{test}}</p>
</body>
</html>
You could probably add Mustache as a rendering engine by following the Express manual:
View filenames take the form “.”, where is the name of the module >that will be required. For example the view layout.ejs will tell the view system to >require(‘ejs’), the module being loaded must export the method exports.compile(str, >options), and return a Function to comply with Express.
Edit:
From the Mustache manual under Usage:
Below is quick example how to use mustache.js:
var view = {
title: "Joe",
calc: function () {
return 2 + 4;
}
};
var output = Mustache.render("{{title}} spends {{calc}}", view);
In this example, the Mustache.render function takes two parameters: 1) the mustache >template and 2) a view object that contains the data and code needed to render the >template.
From the above I suspect you could just export Mustache.render, but I haven't tested it. The object literals used as data look the same, but if they do happen to be different, you could probably just wrap Mustache.render in a function that formats it correctly.
Edit: Xomby's wrapper link contains an example of how to wrap handlebars for express, Mustache should be similar.
Try Hogan.js http://twitter.github.com/hogan.js/
I think it's what Twitter and LinkedIn uses in production.
Here's a working example/tutorial on using NodeJS, ExpressJS and MustacheJS Template Engine:
http://devcrapshoot.com/javascript/nodejs-expressjs-and-mustachejs-template-engine
You can build out a complete web page like you normally would, placing the mustacheJS fields where you like. Use express to route to the page, use node fs.readFileSync(); to get the html file, use mustache to update the data on the page then spit it out to the client.
It's kinda neat. I hope it helps!
-A-
Have you already tried stache ? It is no longer maintained but you can follow some links and get more recent stuff ..
I found Handlebars.js which is an extension of the Mustache template system/language.
And there is a really simple wrapper to use it with Express.
Sure, the best way to do this is the post here:
http://iamtherockstar.com/blog/2011/11/21/using-mustache-templates-express-apps/
So far, this has worked great for me. The only problem I have found is not using partials at the root path for views. For example partials in view/partials - the engine by default only finds partials as view. Let me know if you figure that out!
Check out Handlerbars. " Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.
Handlebars is largely compatible with Mustache templates. In most cases it is possible to swap out Mustache with Handlebars and continue using your current templates. Complete details can be found here " - Handlebars

How can express and jade does not compress html?

I using express and jade, but when I debug I doesn't want jade compress my html, are there any way to pass an option jade globally and make it does not compress html.
If you use Express 3.x, you can control compression via app.locals.pretty. I usually enable it while development:
app.configure('development', function () {
app.locals.pretty = true;
});
In the time since this answer was written an option has been added to control this behaviour.
app.locals.pretty = true;
At the moment, no. This feature has been discussed here:
https://github.com/visionmedia/jade/pull/205
The html doesn't actually get compressed or minified by default, though. It's just not formatted nicely. The simplest way I've found to make it human-readable is to use Chrome's dev tools, which give you a nice foldable representation of the source.
You can use Jade Comments to annotate your code for viewing in the browser.
//h1
h1 Some Title
//p
p some content
will output
<!--h1-->
<h1>Some Title</h1>
<!--p-->
<p>some content</p>
The template is already compiled once it leaves the server, so if you wanted to view the template in the browser you would have to write a plugin that de-compiles html to jade and than display the decompiled version.
Huh, new to nodejs so maybe missing something here; but in app.js adding app.set('view options', {pretty: true}); was ineffectual (using express 3.0.3).
..doesn't appear to be supported? did find a workaround, e.g. on a per route basis:
exports.index = function(req, res){
res.render('index', {
[... other stuff ...]
pretty: true
});
};
For whom using pug-cli, you need to add --pretty in cmd(terminal). Like the following,
pug --pretty -w -o dist/html/ assets/pug/index.pug

Passing raw Markdown text to Jade

I'm playing around with my first Node.js Express application, and as every programmer knows, the first thing you should build when testing out a new framework is a blog! Anyway, I'd like to write the articles in Markdown and then render it in the view. I saw that Jade allows for this to be done inside the view itself, using filters, but I can't get that working.
To simplify the situation, here's an example of what I'm talking about.
//app.js
res.render("article", {
md : "Hello World!\n\n*Woo*"
});
//article.jade
section
:markdown
#{md}
But, that outputs this: <section><h1>{md}</h1></section>... it isn't substituting in the variables I've passed to it.
Then I tried this:
//article.jade
section
:markdown
!{md}
And the output is this:
<section><p>Hello World!
*Woo*</p></section>
So, now it's not parsing the markdown!
I have been able to get this to work by parsing the markdown in the app.js file and then passing the HTML to the view to display, but I don't know, that seems a bit messier.
Is there a way to pass variables into Jade filters?
You can do this with a function passed in to jade from node:
var md = require("node-markdown").Markdown;
Then pass it into the view as a local:
res.render('view', { md:md, markdownContent:data });
Then render it in the jade view by calling the function:
!= md(markdownContent)
The node module node-markdown is deprecated. The marked is advanced new version. You can try like this
var md = require('marked');
Inside your router
res.render('template', { md: md });
Inside your jade template
div!= md(note.string)
I don't think jade can do this out of the box. One way to accomplish it that might feel slightly cleaner than pre-rendering the markdown is to create a helper function called markdown that takes a markdown string and returns HTML. Then you could do something like
section
!= markdown(md)
The markdown function should be included in the locals data when you render the jade template and can directly use a markdown library to convert the markdown syntax to HTML.
If you are using Scalate's Jade support you can enter:
section
:&markdown
#{md}
You can also import external files with:
section
:&markdown
#{include("MyFile.md")}

Resources