Only info I found was this:
http://forrst.com/posts/Node_js_Jade_Import_Jade_File-CZW
I replicated the suggested folder structure (views/partials) But it didn't work, as soon as I put
!=partial('header', {})
!=partial('menu', {})
into index.jade, I get a blank screen, the error message I receive from jade is:
ReferenceError: ./views/index.jade:3
1. 'p index'
2. ''
3. '!=partial(\'header', {})'
partial is not defined
I'd be very grateful for any help ! (I strongly prefer not to use express.js)
Jade has a command called include. Just use
include _form
given that the filename of the partial is *_form.jade*, and is in the same directory
As of August 2012 (possibly earlier) Partials have been removed from Express.
A lot of tutorials are now out of date. It seems that you can replicate much of the partial functionality with include.
Eg.
movies.jade
div(id='movies')
- each movie in movies
include movie
movie.jade
h2= movie.title
.description= movie.description
HTH
With the latest node/express I get the following movies.jade template to call partials:
div(id='movies')
- each movie in movies
!=partial('movie', movie)
where I have movie.jade in the views directory alongside movies.jade.
movies.jade is called from app.js with:
res.render('movies', { movies: [{ title: 'Jaws' }, { title: 'Un Chien Andalou' }] });
I think partial rendering is done in express, so you will have to snag that code or write your own.
I have my own helper class for jade rendering with partials that you can use or get some ideas from here, (it's using Joose and Cactus)
Related
I'm looking to use Ghost to host both a blog and a static website, so the structure might look something like this:
/: the landing page (not the blog landing page, doesn't need access to posts)
/blog/: the blog landing page (needs access to posts that index.hbs typically has access to)
/page1/, etc: static pages which will use page.hbs or page-page1.hbs as needed
/blog-post-whatever/, etc: blog posts which will use post.hbs
The only thing I foresee being an issue is that only index.hbs (as far as I know) is passed the posts template variable (see code on GitHub here).
Before I go submit a pull request, it'd be nice to know whether:
Is there an existing way to get access to the posts variable in page.hbs?
If not, is it worthwhile to submit a pull request for this?
If yes, would we really want to send posts to all the pages? or should the pull request split apart page.hbs and only send it to those? or is there a better way to do this?
If you don't mind hacking the Ghost core files then here is how you can do it for the current version of Ghost (0.7.4). This hack will require recreation if upgrading to a new Ghost version.
First create the template files (that will not change if you upgrade):
Create the home page template in:
contents/themes/theme-name/home.hbs
home.hbs now supersedes index.hbs and will be rendered instead of it.
Also create the blog template file in:
contents/themes/theme-name/blog.hbs
The handlebars element that adds the paged posts is
{{> "loop"}}
so this should be in the blog.hbs file.
Again, the above files do not change if you upgrade to a new version of Ghost.
Now edit the following files in the core/server directory:
I have added a few lines before and after the sections of code that you need to add so that you can more easily find the location of where the new code needs to be added.
/core/server/routes/frontend.js:
Before:
indexRouter.route('/').get(frontend.index);
indexRouter.route('/' + routeKeywords.page + '/:page/').get(frontend.index);
After:
indexRouter.route('/').get(frontend.index);
indexRouter.route('/blog/').get(frontend.blog);
indexRouter.route('/' + routeKeywords.page + '/:page/').get(frontend.index);
This calls the Frontend controller that will render the blog page with the same data level as ‘index’ and ‘home’ (the default is load a the first page of the recent posts) thus enabling us to use the “loop” in the /blog/ page.
/core/server/controllers/frontend/index.js
Before:
frontendControllers = {
index: renderChannel('index'),
tag: renderChannel('tag'),
After:
frontendControllers = {
index: renderChannel('index'),
blog: renderChannel('blog'),
tag: renderChannel('tag'),
/core/server/controllers/frontend/channel-config.js
Before:
getConfig = function getConfig(name) {
var defaults = {
index: {
name: 'index',
route: '/',
frontPageTemplate: 'home'
},
tag: {
After:
getConfig = function getConfig(name) {
var defaults = {
index: {
name: 'index',
route: '/',
frontPageTemplate: 'home'
},
blog: {
name: 'blog',
route: '/blog/',
frontPageTemplate: 'blog'
},
tag: {
/core/server/controllers/frontend/channel-config.js
Before:
indexPattern = new RegExp('^\\/' + config.routeKeywords.page + '\\/'),
rssPattern = new RegExp('^\\/rss\\/'),
homePattern = new RegExp('^\\/$');
After:
indexPattern = new RegExp('^\\/' + config.routeKeywords.page + '\\/'),
rssPattern = new RegExp('^\\/rss\\/'),
blogPattern = new RegExp('^\\/blog\\/'),
homePattern = new RegExp('^\\/$');
and
Before:
if (indexPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('index');
} else if (homePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('home');
res.locals.context.push('index');
} else if (rssPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('rss');
} else if (privatePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('private');
After:
if (indexPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('index');
} else if (homePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('home');
res.locals.context.push('index');
} else if (blogPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('blog');
} else if (rssPattern.test(res.locals.relativeUrl)) {
res.locals.context.push('rss');
} else if (privatePattern.test(res.locals.relativeUrl)) {
res.locals.context.push('private');
Restart the server and you should see the new /blog/ page come up with the list of recent blog posts
Here's a solution that I am currently using. I have an off-canvas nav that I want to use to display links to my latest posts. On the home page, this works great: I iterate over posts and render some links. On the other pages, I don't have the posts variable at my disposal.
My solution is this: wrap the pertinent post links on the homepage in a div with an id of "posts", then I make an ajax request for that specific content (using jQuery's load) and inject it into my nav on all other pages except the home page. Here's a link to jQuery's load docs.
Code:
index.hbs
<div id='posts'>
{{#foreach posts}}
<li>
{{{title}}}
</li>
{{/foreach}}
</div>
app.js
var $latest = $('#posts');
if ( location.pathname !== '/' )
$latest.load('/ #posts li');
There is no way currently (Ghost v0.5.8) to access posts within a page template.
I would think its probably not worth submitting the pull request. The Ghost devs seem to have their own plans for this and keep saying they'll get around to this functionality. Hopefully its soon because it is basic functionality.
The best way to go about this would be to hack the core yourself. Eventually the better way to do this would be with a hook. It looks like the Ghost API will eventually open up to the point where you can hook into core functions for plugins pretty much the same way Wordpress does it. https://github.com/TryGhost/Ghost/wiki/Apps-Getting-Started-for-Ghost-Devs
If this is a theme others will be using I would recommend working within the current limitations of Ghost. It's super annoying, I know, but in the long run its best for your users and your reputation.
If this is only for you, then I would hack the core to expose a list of posts or pages as locals in each route. If you're familiar with Express then this shouldn't be very difficult.
I think the way you've done it is pretty creative and there's a part of me that likes it but it really is a seriously ugly hack. If you find yourself hacking these kinds of solutions together a lot then Ghost might not be the tool you want to be using.
A better solution than briangonzalez one, is to get the posts-info from the RSS-feed, instead of the home page.
See this gist for how it can be done.
Now you can use the ghost-url-api, it's currently in beta but you can activate it in the administration (Settings > labs).
For example the {{#get}} helper can be use like this in a static page:
{{#get "posts" limit="3" include="author,tags"}}
{{#foreach posts}}
... call the loop
{{/foreach}}
{{/get}}
More informations :
http://themes.ghost.org/docs/ghost-url-api
As of Ghost v0.9.0, the Channels API is still under development. However, achieving this is much simpler now. It still requires modification of core files, but I'm planning on submitting some pull requests soon. Currently, one downside of the following method is that your sitemap-pages.xml will not contain the /blog/ URL.
Thanks to #Yuval's answer for kicking this off.
Create a template file for your index page with the path content/themes/theme-name/index.hbs. This can contain whatever you would like for your "static" homepage.
Create a template file for your blog index page with the path content/themes/theme-name/blog.hbs. This simply needs to contain:
{{> "loop"}}
In /core/server/controllers/frontend/channel-config.js:
Edit the var defaults object to include:
blog: {
name: 'blog',
route: '/blog/'
}
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.
I am posting this questions after reading this similar SO question
I have a node.js app running which uses Express 2.5.8 and Jade 0.26.0
I have a jade page that will consist of many widgets. On scouring the internet it seemed ideal to use partials to modularize these widgets.
So my jade main page called comp.jade is
!!! 5
html(lang='en')
head
body
h2.page-header REPORT FOR #{comp_name}
.other_ds
partial('partials/ln_profile')
And my ln_profile.jade is
p.ln_profile
strong #{comp_ln_name}
br
| #{comp_description}
On the server side my script looks like
res.render('comp',{comp_name: 'Some Company'}); // to pass data to comp.jade
res.partial( 'partials/ln_profile',{comp_ln_name: 'Test Company',comp_description:'Test Description'}); // to pass data to ln_profile.jade
But when I do this only ln_profile.jade gets rendered and the comp.jade is not getting rendered.
Where am I going wrong here ?
Partials is deprecated. You have to use Include statement instead of partials.
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
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")}