Can I pass data to a handlebars partial? - node.js

I'm making a website in Node JS, and want to display something from the database on the website.
When I fetch the data in node, I pass it of to an html page (an hbs file) using express as the second argument in res.render().
However, that html page (hbs file) which I pass the data to, contains a partial, is it possible to pass that same data which was passed to the hbs file, to the partial that is in that hbs file?
Important code for reference:
Passing the data to the hbs file:
app.get('/about',async (req,res)=>{
const names = await Category.find({});
res.render('about',{
categories:names
});
})
Then I'd like to do something like this
{{>header,{{categories}}}} in order to access the categories data in the partial.

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.

Sending data to header.ejs using Nodejs

I send data to my Nodejs pages doing something like:
res.render("mainPage.ejs",{myArray})
However, I have a situation where I want to change set the navbar dropdown values using some values form my database.
I wanted to know if is possibile to send data to every header.ejs file using Nodejs.
Like Handlebars, ejs also has the concept of partials.
Check out the official doc. here:
https://www.includehelp.com/node-js/ejs-partials.aspx
You can pass the data to the views by doing something like this:
router.get('/routeHere', (req,res)=>{
res.render('pages/blog',
{
key1: value1,
key2: value2
});
});
You will then be able to access the object under 'res.render()' in the view.
You don't "send data to a partial". You pass data into your temaplate res.render('mytemplate', { user }) and user is available to each partial you included in mytemplate.ejs. Included partials see their parent template data.

What does app.engine() do ? And what are ext and callback?

I tried reading through the documentation and they said
app.engine(ext, callback)
Register the given template engine callback as ext By default will require() the engine based on the file extension. For example if you try to render a "foo.jade" file Express will invoke the following internally, and cache the require() on subsequent calls to increase performance.
I am having a tough time figuring out what do ext and callback here even mean.
This is part of the view/template engine functionality of Express. Many times your request handlers only return some JSON object. But other times you want to build a regular "document" like a fully built HTML page, or RSS feed etc. Template engines help you achieve this, though they are by no means mandatory. You could use other approaches (build strings by hand for example, if you like the pain), or you could use a library such as pug/moustache etc by hand. The view engine functionality basically integrates libraries such as pug/moustache into express so it's easier to use them.
The linked page has a nice example of how this would be used in practice:
Then create a route to render the index.pug file. If the view engine property is not set, you must specify the extension of the view file. Otherwise, you can omit it.
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!' })
})
When you make a request to the home page, the index.pug file will be rendered as HTML.
Many times express knows about various template engines. So it's enough to say express.set('view engine', 'pug') and it can do the right thing as long as the pug package is installed.
Other times you need to use app.engine to tell it more explicitly what to do. It is called like app.engine('jade', require('jade').__express). The first parameter is just the extension express should be looking for. So when you say req.render('index', ...) it would look for an index.jade file. The second parameter is the function which actually does the integration between the view engine (which, as I've said, is a separate thing from express), and express itself. consolidate.js is a package with integrations for a lot of view engines.
But if you want to see what this function does, checkout developing template engines for Express. The callback parameter must look like function(filePath, options, callback). filePath is just the name of the disk file to use for rendering, so index.jade in the example from above. callback is a standard node callback, invoked as callback(err) on error or callback(null, renderedContent) on success. options is an object passed in from the req.render('index.jade', /* options */ { title: 'foo', content: 'bar' }). It's then up to you to decide how to actually do the rendering based on the supplied arguments.
In simple terms: ext - extension, callback - library (engine) that will render the file with the given extension.

Create PDF using Node.js, Jade and Express

I'm trying to create a PDF from one of my views.
This view is rendered using Jade and Express, loads some Javascript, some CSS files, extends some Jade views, and queries a database to populate different graphs. The rendering process takes about 7 seconds because it is not very well optimized.
Additionally, the GET request for the view uses passport and connect-ensure-login to verify that the user is logged in before rendering and passes some variables for Jade to use when rendering. This is the handler code:
var express = require('express');
var router = express.Router();
var moment = require('moment');
router.get('/', require('connect-ensure-login').ensureLoggedIn(), function (req, res, next) {
res.render('summary', {
title: 'Summary',
day: moment().format('D'),
month: moment().locale('es').format('MMMM'),
year: moment().format('YYYY')
});
});
module.exports = router;
This is the Jade file that needs to be converted to PDF:
extends layout
block content
.container-fluid
#banner
.chart#chart1
.chart#chart2
.chart#chart3
script(type='text/javascript', src='/javascripts/summary.js')
And this is the Jade file (layout) that is extended:
doctype html
html
head
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(http-equiv='content-type', content='text/html; charset=UTF-8')
meta(content='width=device-width, initial-scale=1', name='viewport')
title=title
link(rel='stylesheet', type='text/css', href='/stylesheets/styles.css')
script(type='text/javascript', src='/assets/jquery-3.1.1/jquery-3.1.1.min.js')
script(type='text/javascript', src='/assets/bootstrap-3.3.7/js/bootstrap.min.js')
body
.page-wrapper
block content
How would I go about loading the page and taking a screenshot and converting it to a PDF or rendering it as a PDF from the Jade file?
I've heard of PhantomJS but I can't find information that is up-to-date.
If anyone could help me out I would be very grateful.
What you can do, is use the jade/pug to generate the .html file with the desired values, save it in the File System (Async way) once this is done, use this library:
https://www.npmjs.com/package/html-pdf
To Read (Async way) the .html file that you saved in the file system and convert it into a pdf, and finally, stream it to the client.
Maybe you can use another library to instead of write to the File System, pipe it directly to the PDF converter, and it will be faster.
If the template will change frequently, this will have to be done for every request, otherwise, you can cache it, and only generate it the first time, then detect if is already there and pipe it to the response.
Hope it helps.

how can we define static variable and call in html file in node.js?

I want to define variable in app.js file then after use this variable in whole/any html page.
Fore example:
app.js
var title = 'mytask';
index.html
<%=title%>
You can easily do the same using ejs
But if you want to use the varibale on hmtl page, you need to pass the title while rendering the page .
Say there is an "index.html"
res.render("index", {title :title});
now you can easily use the title variable in index.html
<div>{{title}}</div>
What you're looking for is called a local variable. If you're using Express (which I assume you do), then you have two kinds of locals, which are both sent to the views automatically, without passing them manually in each of your routes:
app locals: these are alive persistently for the entire lifetime of the application, you can use them anywhere where the app object is in scope. (more info)
response locals: these are tied to the lifecycle and scope of a single request/response object (more info)

Resources