How to register a Handlebars partial outside partials folder on Sails.js? - node.js

I have the following folder structure on my Sails.js application:
assets/
myModule/
views/
partials/
Where myModule is a Backbone component (although my client is not a full Backbone application)
There's a given Handlebar partial x.handlebars that need to be rendered both via server and client sides.
My struggle starts when views/ is not accessible on client side so there's no way to load it on Backbone module.
Then I have tried to move it to assets/myModule/templates/ which would be accessible but now my main template views/layout.handlebars can't load that partial if I try something like:
{{> ../assets/myModule/templates/x}}
which doesn't work as well (I assume Handlebars use views/ as root level for the layouts).
There's only two possible solutions I'm seeing in that situation:
Duplicate these layouts and use one on each location (not ideal, but works)
Place it on assets/myModules/templates/x and register a Handlebars partial on Sails to let it available for the server-side rendering.
How could I do that second solution? Is that possible to register a global partial the same way we can do it with the helpers function under config/views.js?
My goal is to use Handlebars.registerPartial function on config level, outside a Controller so that partial could be reused by other templates as well.

Duplicating the code is not necessary. There are many different ways you can implement this and depends on the optimization profile you will be looking for.
A simple solution would be to read the hbs file in the api/controller with node's fs, then compile it with Handlebars and pass it to the template like this:
var rawTemplate = fs.readFileSync('assets/hbs/client-side-template.hbs', "utf8");
var processedTemplate = Handlebars.compile(rawTemplate);
return res.render('whiteboard/dualloadview', {
myPartialAsVariable: processedTemplate({})
});
You'll have have to figure out how to handle the context and variables used by the partials. You can also improve on this code snippet to by looking into keeping the file read in memory, and looking into how to register partials with Handlebars instead of using a variable.

Related

Why res.render() doesn't send local variables to the client without template engine?

I need to access the variable user in my client-side that sent by
res.render('home.html', { user: req.user });
without using template engines like pug or ejs
Is that possible?
HTML is not a templating language, so it can't be used to send variables.
res.render() function compiles your template , inserts locals there, and creates html output out of those two things. The syntax is as follows -
res.render(view [, locals] [, callback])
The view argument is a string that is the file path of the view file to render. For this to work, you need a template or view engine .
In html, you can't dynamically pass/insert data variables. That's the main use case for templating engine. They put runtime/dynamic value in html which is what you are probably looking for.
In short, its better to use any template engine like pug,jade,ejs, etc most of which would have almost similar syntax with html to render dynamic html pages. I don't think there's any method (atleast simple enough) to send variables dynamically from server to client in an html page. Using a template engine would be the best choice in your use case.
For eg. you are passing user from server side and most probably want the passed variable to be rendered on the client side. You can just install an view engine like ejs - npm install ejs, set your view engine in app.js - app.use('view engine','ejs'); , and just add this line in the html page where you want to send the variable to client side like - <p> <%= user %> </p> and that's it. Keep your html file in view folder and this would do it.

Pug template inheritance with different paths (and depths)

I am running into the problem that I have a 'main layout' which gets extended by other pug files, defining the layout for specific sites.
Example:
main.pug
Path: /we [we.pug extends main.pug]
However, when I start to have routes like /we/are/nice/because which are just specifications of /we and I would like to use the same main.pug, I run into the problem that by the way NodeJS renders the pug files, the src/href paths of JS and CSS includes are off (eg: https://localhost:3001/we/are/nice/script.js won't be found because it is supposed to be at localhost:3001/script.js)
Is there a simple way to fix this issue, or do I need specific main.pug files for all path-depths ?
Have you tried pointing to absolute paths? So /script.js, instead of script.js, in an link/href attribute. This assumes, of course, that the files are served from a server like NodeJS (not by the filesystem).

How can I use Express to render dynamic files?

I'm looking to use Express to render raw strings as HTML, with the ability to reference static files in a specified directory (CSS, images, and other resources).
I've done a lot of research, but I haven't seen anything that approaches what I'm trying to do. For example, I thought perhaps writing a custom templating engine that only pretended to load a file would cut it, but that doesn't seem to do the trick.
What's the best way to approach this?
There are many ways to do it.
It can done in any other templating engine as well but here i am guiding you to implement same using EJS(Embedded Javascript).
Use Express Generator to create an ExpressJS app with EJS templating Engine.
command :
express --ejs AppName
For more information about express Generator refer to doc here
Now EJS has tags such as :
1. <% code %> - Code that is evaulated without "echo" it is not printed out.
2. <%= code %> - Code that is evaluated and printed out and escaped!
3. <%- Code %> - Code that is evaluated printed out and not escaped!
So in your case you can use 3rd the third tag that i have mentioned above.
Render EJS views in the usual way from your route config:
res.render('index.ejs', {
// data you want to pass ..
});
Code sample
Some time ago i was playing around with EJS, i developed a very small blogApp for practice.
You can look into this view, line number 33, for more practical way of implementing same.

Why do you need a templating language with Node.js?

After doing some research, everyone seems to advise learning and using some form of a templating language with node.js. Why? Couldn't you just use HTML, and if so, how? I'm new to Node, so I downloaded Express and immediately I asked myself, "What is .jade?"
There is no requirement, but it can be much nicer. You can just as easily manually output HTML, but then you are forced to keep all of your HTML inside of JS strings at all times, or keep it in a file.
You'd do something like this:
res.send("<html><body>" + content + "</body></html>");
As soon as you want to have dynamic HTML, you either need to include it directly in your code, or you need to have it in a template. The difficulty is that you can't just throw standard HTML in a file, because that essentially makes it impossible to dynamically alter the page. To solve this problem, usually you'd dynamically generate HTML using some kind of templating language like jade.
For a tiny one-off app, it may not be a big deal, but separating your presentation HTML from your code becomes very important as the size of the app you are developing grows.
If your're using express use the code below
var express = require('express');
var app = express.createServer(
express.static(__dirname + '/public')
);
app.listen(3000);
Then put all your html files in the /public folder. That's it.

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