I have created a layout and partial folder in views. I didn't understand why this code is used in app.js - node.js

app.engine('hbs',hbs({extname:'hbs',defaultLayout:'layout',layoutsDir:__dirname+'/views/layout/',partialsDir:__dirname+'/views/partials/'}))
why is hbs,extname,defaultLayout used here

app.engine(ext,callback) will takes two arguments, one is the extension and the other is a callback function. Therefore, hbs is the extension you are using to create your views.
you can also take a look at handelbars's github repository when they mentioned extname from here.
https://github.com/ericf/express-handlebars#extnamehandlebars
This link also might be helpful for you, they mentioned the defaultLayout option and what it means.
This link might help you understand why to use defaultLayout.
A layout is simply a Handlebars template with a {{{body}}} placeholder.
Usually it will be an HTML page wrapper into which views will be
rendered.
https://github.com/ericf/express-handlebars#layouts

Related

Inject meta tag dynamically to HTML with Express

Summary:
I'm currently migrating a website on Apache + PHP stack over to Node + Express, and would like to know what is the best way/best practice (if there is one) for dynamically injecting meta tags under the new stack.
Details:
Under the existing stack, meta tags are injected dynamically by adding PHP codes into the HTML file directly. As rendering is done on server side, the tags are properly interpreted by Facebook/Google+/whatever web crawlers.
Under the new stack, after doing some research, I've come across two options:
Use template engine like Pug (Jade) to render the HTML with locals. (It seems to be an overkill to rewrite the existing HTML with Pug's syntax though? Can Pug deal with HTML, or I've to consider other template engine like EJS? What template engine do you advise me to explore?)
Use DOM manipulation plugin like Cheerio to inject the meta tags first, before rendering begins.
Between these two options, which one will have a better performance or there is no material difference? Are there any other ways that you'd otherwise recommend? Thanks!
EJS would probably be the simplest one for that and very similar to PHP.
You can also take a look at Mustache and Handlebars for other options with minimal changes to your existing HTML.
with EJS: <html><head><%= yourMetaTags %> ...
with Mustache: <html><head>{{ yourMetaTags }} ...
with Handlebars: <html><head>{{ yourMetaTags }} ...
Also doT.js is very fast.
See:
http://www.embeddedjs.com/
https://mustache.github.io/
http://handlebarsjs.com/
http://olado.github.io/doT/
Parsing the HTML and manipulating it with a DOM API just to insert meta tags would be an overkill in my opinion.
On the other hand if all you need is to insert meta tags then you could make a simple regex substitution, using something like yourHTML.replace('<head>', '<head>'+yourMetaTags); but it could potentially get more complex over time when you need more functionality. After all, everyone has made a templating engine at some point in life.

Adding additional content blocks in KeystoneJS with handlebars

I'm using handlebars with KeystoneJS and am trying to extend the main import in the default template. At the moment it only includes the {{{body}}} tag imported through the view plus the partials that I'm using.
Is there any way to add a couple of other imports (i.e. intro content, page title, additional scripts). In the jade version on the demo site it just imports it as a content block. Is this a limitation of handlebars?
You can do this with handlebars just fine using partials.
Put your partial in the folder indicated below:
Then in your layout ('default.hbs' in this case) reference the partial like you would normally in handlebars.
<div id="header">
{{> navigation this}}
</div>
The '>' means insert partial.
In this case 'navigation' is the
partial name in the partials folder.
'this' is the data context. Its what you want to do with the 'locals.data' object passed into handlebars by keystone. Using 'this' will pass the whole lot through whereas doing something like 'locals.data.navigation' would pass the navigation object through to the partial making it directly accessible in the partial (good for DRY).
Hope that helps. The partials specific documentiation for handlebars is here if you are interested in looking into a few more things you can do with scope etc http://handlebarsjs.com/partials.html

Render partial view with jade on select change

I need to do the following,
I have a <select> (a list of team names), when the user selects a team, I get relevant information re: the team and display it.
How do I do this in jade?
I'm trying the following, (but I'm wrong obviously, I don't see a lot of documentation out there).
Briefly, I'm doing a include test.jade on my main page, and a res.render('test', {team: team_obj});
jade:
h1 #{team}.name
h2 #{team}.homeGround
h3 #{team}.manager
h4 #{team}.aka
nodejs:
collection.findOne(query, function(err, team_obj){
res.render('test', {team: team_obj});
});
I'm getting the information correctly in team_obj.
Get the following error when I run the app,
team is not defined
Now this is happening because test.jade is getting rendered before I feed it the team_obj.
Questions:
1) Am I doing this right? is include the correct way of partially rendering jade views? if yes, how do I make sure it renders only when the user has selected an option?
2) Is there a partial views concept in jade I'm unaware of?
1) you should use #{team.name}
2) you can't change the team object once the selector is changed. the template was rendered once with the database result. - such functionality should be handled by client side JavaScript and AJAX calls. partials in templates are just a way to share common pieces of templates, and its done in Jade via include.
I don't know what you're rendering and including and when.. but id you use a template variable like #{team.name} you have to make sure that the template was rendered with the team object.

Dust.js partails newbie

I have piece of code which I want to use in some of the dust templates, so i am planning to use partials. I am not sure if following is the best approach. Please help.
1) I extracted common code from base templates in to a template file called userinfo.html
2) I compiled userinfo.html to create userinfo.dust
3) I added {>"userinfo.dust"/} code into all templates where I wanted to see user information.
4) Now when I render the template with following command. I get "Template not found: userinfo.dust" error.
dust.render("moduleTemplate", templateData, function(err, out) {
$main.html(out);
});
Do, I need to send userinfo.dust along with templateData while rendering? I tried reading all partial related information which google can give me, but not able to to figure how to implement partials.
In your template, when you call:
{>"userinfo.dust"/}
You should really be calling
{>"userinfo"/}
As yo don't need to specify the .dust extension. Here's a template example of mine:
{>header /}
{>results /}
{>footer /}
HTH
It sounds like the answer to your problem is that the partial is not being included on the page. Dust compiles to JavaScript, so this will make more sense if you rename your files: userinfo.dust (the template), and userinfo.js (the compiled template). Now include your template using a script tag:
<script type="text/javascript" src="templates/userinfo.js"></script>
Finally, you need to call the template using the svame name it was compiled with. It is a good idea to use the filename (often but not necessarily without the extension):
var userinfoCompiled = dust.compile('userinfo', 'user info template goes here');
A template compiled in this way can be called using:
{>userinfo/}
If you're not sure what your compiled template's name is, you can open the compiled JavaScript file and look for:
dust.register('userinfo')

How to provide the current route or view to the layout in ExpressJS?

I want to be able to dynamically reference JavaScript and Stylesheets depending on which page a user is on in Express. I thinking the best way to do so (though I'm open to suggestions) is to pass the current view to the layout page.
For example;
Given the url http://example.com/trees
I would want to have some logic in layout.jade that said something to the effect of:
script(src="/javascripts/{view}.js")
Which would get rendered as:
<script src="/javascripts/trees.js"></script>
Any suggestions or best practices for doing this?
req.route is the matched route, so things like req.route.path etc are available, or of course req.url which may be parsed. With express 2x you can expose these values to views automatically using "dynamic helpers" or res.local()
There are no best practices for doing this, since Express doesn't provide Rails like url helpers, so I think you're approach is fine.
The easy answer is to just put ALL your javascript into a single file and be done with it. Ditto for CSS. See the Ruby on Rails asset pipeline for details. You are probably making your life more complicated than necessary and also less efficient by having different javascripts on different pages.
However, since you asked, the answer for javascripts is easy. Just put the extra <script> tags in the view, not the layout. Problem solved. CSS doesn't work as cleanly because the <link> tags need to be inside the <head>. In this case, I define the styles I need as an array of strings and loop over that in my layout template. So in my route I set up a local variable such as
locals.css = ['/css/one.css', '/css/two.css']
Then just loop over that in your template and generate one <link> tag for each.

Resources