Get name of template inside a pugjs template - node.js

I'm rendering my pages with pugJS like this:
res.render('test',renderVars)
This render uses a layout, in which I need to get the 'test' string. My question is: how can I get the 'test' string so that I can use it in my layout? I could put a new variable in 'renderVars' but I'm sure there is a better solution.
In other words: how can I get the name of a template inside this template? Something like #{templatename} for example?
Thanks in advance!

I'm afraid you can't do so. res.render 1st parameter is rendering a view template not mean to store data. You could set the 'test' in renderVars or you can add it in session and will be able to use it in your layout.
Add this code into your app.js before the routes and after session settings
//inject session into res.locals so can be rendered in UI
app.use(function (req, res, next) {
if (req.session.message) {
res.locals.message = req.session.message;
delete req.session.message;
}
res.locals.session = req.session;
next();
});
In the view template you can access the res.locals.session data by using
#{session.theAttributeYouWant)

Related

Node express api routes for multilingual directory like url

Does any one knows an example or could explain here how node.js and express would have to route for a multilanguage site? I'm using i18n-node for translation and folder like routing ( /es/, /de/ , etc ) for different languages. This all are static routes but I also have routes like apiRoutes.route('/user/profile') using 'app' at the begining ( app.get('/app/user/profile') so please consider this in your answer so is NOT necesary route to : app.get('/es/app/user/profile') .
having 15 routes like this now:
app.get('/terms', function(req, res) {
res.render('terms',{
...
});
});
how it have to be set for routes like:
app.get('/es/terms', function(req, res) {
res.render('terms',{
...
});
});
Should I duplicate this routes and add for example a locale for
each like:
app.get('/es/terms', function(req, res) {
res.render('terms',{
...
});
});
Or Should do something like:
if cookie['lang'] && cookie['lang'] is in locales
// then redirect to /:lang/terms
else
// show default language in /terms
if req.headers["accept-language"] && req.headers["accept-language"]
// then redirect to /:lang/terms
else
//show default language in /terms
Or there is another way I should approach this that follows good practices or is better respecting standards?
Miro's Answer in :
How can I get the browser language in node.js (express.js)? says I should use app.all('*', ...
Is this all I need?, ..still, it might have a syntax error or i'm not understanding well this two parts
var rxLocal = /^\/(de|en)/i;
...
app.get(/\/(de|en)\/login/i, routes.login);
thanks in advance
You need to consider 2 things :
1. How get the local :
Accept-Language
The HTTP protocole define the Accept-Language header to manage the local. This is a normalized method. You can access it with the req.acceptsLanguages method of express.
+Normalized
+Natively support by brower
-Not easy to by passe by the end user
Path / Cookies
You can get the local from the path. In express it can be do with a parameter patter like /:local/rest/of/path and retrieve in the request object with the req.param method.
You can also get the information from the cookies with the req.cookies properties (don't forgot to set it).
Both
To increase the user experience you can mix the both method. For exemple get the default language from the HTTP header send by the browser but permite to the user to override this in you application and store this parameter in the cookies.
2. Use the local:
Each methods to get the local can be used from different way. I will
use random of them in exemple but they are all compatible.
Top level configuration.
In case of you use a template Engine and you controller can be local agnostic. You can use a middleware to get the local information and configure the render engine.
app.use('/:local' (req, res, next) => {
let localKey = req.param('local');
res.locals = // Some ingenious method to get the locales from localKey
next();
}
Check res.locals and your engine documentation.
Use it in controller.
If the local is part of the contoller process. You can get directly is value in controller.
In case of you use a complexe method to determine the final value of the local, you can also use a middleware to determine this value and enrich the request with it.
app.use((req, res, next) => {
let local = req.cookies.local;
if(!local) local = req.acceptsLanguages();
if(!local) local = 'en-US';
req.local = local;
}
Both
You can use both method too. It depend of what you need. Find the best way to get a maintainable code and avoid replication for your use case.
When you use middle where witch impact the controllers, be sure you declare them before your routes.
You can use a route parameter to get the locale from the URL, like this:
app.get('/:lang/terms', function (req, res) {
if (req.params === 'es') {
res.send('¡Hola!');
else {
res.send('Hi!');
}
});
The colon character tells Express to put whatever is between the first to slashes of the path in req.params.lang.
See express routing documentation for details.

What is meaning of locals in res.render (node.js)?

what is difference between below two code block in Node.JS (express + ejs)?
res.render('demo', {locals:{"variable":data}});
AND
res.render('demo', {"variable":data});
When to use which one? can any one please help me out in this.
The correct way of passing variables to the view is the wollowing
res.render('demo', {"variable":data});
Then you have an objet res.locals Which you can append data and it will be passed to the view.
For example if you have a middlewere for the authentication, you can set the auth variables even before the request arrives in your route.
app.use(function(req, res, next){
res.locals.user = req.user;
res.locals.authenticated = ! req.user.anonymous;
next();
});

How to create global variables accessible in all views using Express / Node.JS?

Ok, so I have built a blog using Jekyll and you can define variables in a file _config.yml which are accessible in all of the templates/layouts. I am currently using Node.JS / Express with EJS templates and ejs-locals (for partials/layouts. I am looking to do something similar to the global variables like site.title that are found in _config.yml if anyone is familiar with Jekyll. I have variables like the site's title, (rather than page title), author/company name, which stay the same on all of my pages.
Here is an example of what I am currently doing.:
exports.index = function(req, res){
res.render('index', {
siteTitle: 'My Website Title',
pageTitle: 'The Root Splash Page',
author: 'Cory Gross',
description: 'My app description',
indexSpecificData: someData
});
};
exports.home = function (req, res) {
res.render('home', {
siteTitle: 'My Website Title',
pageTitle: 'The Home Page',
author: 'Cory Gross',
description: 'My app description',
homeSpecificData: someOtherData
});
};
I would like to be able to define variables like my site's title, description, author, etc in one place and have them accessible in my layouts/templates through EJS without having to pass them as options to each call to res.render. Is there a way to do this and still allow me to pass in other variables specific to each page?
After having a chance to study the Express 3 API Reference a bit more I discovered what I was looking for. Specifically the entries for app.locals and then a bit farther down res.locals held the answers I needed.
I discovered for myself that the function app.locals takes an object and stores all of its properties as global variables scoped to the application. These globals are passed as local variables to each view. The function res.locals, however, is scoped to the request and thus, response local variables are accessible only to the view(s) rendered during that particular request/response.
So for my case in my app.js what I did was add:
app.locals({
site: {
title: 'ExpressBootstrapEJS',
description: 'A boilerplate for a simple web application with a Node.JS and Express backend, with an EJS template with using Twitter Bootstrap.'
},
author: {
name: 'Cory Gross',
contact: 'CoryG89#gmail.com'
}
});
Then all of these variables are accessible in my views as site.title, site.description, author.name, author.contact.
I could also define local variables for each response to a request with res.locals, or simply pass variables like the page's title in as the optionsparameter in the render call.
EDIT: This method will not allow you to use these locals in your middleware. I actually did run into this as Pickels suggests in the comment below. In this case you will need to create a middleware function as such in his alternative (and appreciated) answer. Your middleware function will need to add them to res.locals for each response and then call next. This middleware function will need to be placed above any other middleware which needs to use these locals.
EDIT: Another difference between declaring locals via app.locals and res.locals is that with app.locals the variables are set a single time and persist throughout the life of the application. When you set locals with res.locals in your middleware, these are set everytime you get a request. You should basically prefer setting globals via app.locals unless the value depends on the request req variable passed into the middleware. If the value doesn't change then it will be more efficient for it to be set just once in app.locals.
You can do this by adding them to the locals object in a general middleware.
app.use(function (req, res, next) {
res.locals = {
siteTitle: "My Website's Title",
pageTitle: "The Home Page",
author: "Cory Gross",
description: "My app's description",
};
next();
});
Locals is also a function which will extend the locals object rather than overwriting it. So the following works as well
res.locals({
siteTitle: "My Website's Title",
pageTitle: "The Home Page",
author: "Cory Gross",
description: "My app's description",
});
Full example
var app = express();
var middleware = {
render: function (view) {
return function (req, res, next) {
res.render(view);
}
},
globalLocals: function (req, res, next) {
res.locals({
siteTitle: "My Website's Title",
pageTitle: "The Root Splash Page",
author: "Cory Gross",
description: "My app's description",
});
next();
},
index: function (req, res, next) {
res.locals({
indexSpecificData: someData
});
next();
}
};
app.use(middleware.globalLocals);
app.get('/', middleware.index, middleware.render('home'));
app.get('/products', middleware.products, middleware.render('products'));
I also added a generic render middleware. This way you don't have to add res.render to each route which means you have better code reuse. Once you go down the reusable middleware route you'll notice you will have lots of building blocks which will speed up development tremendously.
For Express 4.0 I found that using application level variables works a little differently & Cory's answer did not work for me.
From the docs: http://expressjs.com/en/api.html#app.locals
I found that you could declare a global variable for the app in
app.locals
e.g
app.locals.baseUrl = "http://www.google.com"
And then in your application you can access these variables & in your express middleware you can access them in the req object as
req.app.locals.baseUrl
e.g.
console.log(req.app.locals.baseUrl)
//prints out http://www.google.com
In your app.js you need add something like this
global.myvar = 100;
Now, in all your files you want use this variable, you can just access it as myvar
One way to do this by updating the app.locals variable for that app in app.js
Set via following
var app = express();
app.locals.appName = "DRC on FHIR";
Get / Access
app.listen(3000, function () {
console.log('[' + app.locals.appName + '] => app listening on port 3001!');
});
Elaborating with a screenshot from #RamRovi example with slight enhancement.
you can also use "global"
Example:
declare like this :
app.use(function(req,res,next){
global.site_url = req.headers.host; // hostname = 'localhost:8080'
next();
});
Use like this:
in any views or ejs file
<%
console.log(site_url);
%>
in js files
console.log(site_url);
With the differents answers, I implemented this code to use an external file JSON loaded in "app.locals"
Parameters
{
"web": {
"title" : "Le titre de ma Page",
"cssFile" : "20200608_1018.css"
}
}
Application
var express = require('express');
var appli = express();
var serveur = require('http').Server(appli);
var myParams = require('./include/my_params.json');
var myFonctions = require('./include/my_fonctions.js');
appli.locals = myParams;
EJS Page
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title><%= web.title %></title>
<link rel="stylesheet" type="text/css" href="/css/<%= web.cssFile %>">
</head>
</body>
</html>
Hoping it will help
What I do in order to avoid having a polluted global scope is to create a script that I can include anywhere.
// my-script.js
const ActionsOverTime = require('#bigteam/node-aot').ActionsOverTime;
const config = require('../../config/config').actionsOverTime;
let aotInstance;
(function () {
if (!aotInstance) {
console.log('Create new aot instance');
aotInstance = ActionsOverTime.createActionOverTimeEmitter(config);
}
})();
exports = aotInstance;
Doing this will only create a new instance once and share that everywhere where the file is included. I am not sure if it is because the variable is cached or of it because of an internal reference mechanism for the application (that might include caching). Any comments on how node resolves this would be great.
Maybe also read this to get the gist on how require works:
http://fredkschott.com/post/2014/06/require-and-the-module-system/

access req in expressjs 3 views

Is it possible to access my query params in my views in ExpressJS 3?
I have a url: http://example.com?search=blah
And in my view I would like to access the search param
I can pass it as a locals but wondering if I can access it directly - my experiments were not successful.
Not looking for the pros and cons of direct access - just want to know if it's possible and how.
Here are a few ways to access req.query from your view:
Set it as a local in the call to render
function(req, res) {
res.render('myview', {query: req.query});
};
in your view you can access search as query.search.
Set res.locals
function(req, res) {
res.locals.query = req.query;
res.render('myview');
};
in your view you can access search as query.search.
Use middleware
This is similar to the previous example but we can use middleware in a reusable way.
function(req, res, next) {
res.locals.query = req.query;
next();
};
Any route that uses the above middleware, will have res.locals.query set.
edit
It appears that I misunderstood the question. The intent was to see if the request data could be accessed without use of the above techniques. As far as I know, it can not. Hopefully the above will still be useful for some readers.
I am pretty sure only locals get passed to the view.
Not looking for the pros and cons of direct access - just want to know if it's possible and how.
There are no pros and cons. It's like saying I want to multiply 15 with 0 but I don't want the answer to be apple.
middleware:
function(req, res, next) {
res.locals.param = req.param;
next();
};
view:
<%= param.search %>

Express.js Middleware - Adding items to the response object model

I'm playing around with Expressjs and am attempting to extract the page title from the default template to middleware instead of passed into the view's model each time.
Default index.jade template
h1= title
p Welcome to the #{title}
Default route from template
exports.index = function(req, res){
res.render('index', { title: "Express" });
};
I attempted the following but get an error from Express saying title is undefined when I do this.
module.exports = function(req, res, next){
res.title = 'Express';
next();
}
This is obviously a trivial example but it's also something that I am trying to figure out since there will probably come a time where I want to inject things into the response's model after each route. I just cannot figure out how to do such.
Thanks
You have to use default helpers. Read the documentation. Here's a simple snippet:
app.helpers({
title: 'Express'
});
/* Now JADE sees your variable title
without explicitly defining it
in every view. */
Also look at dynamic helpers in the documentation. These can be linked to req and res variables (normal helpers do not depend on request/response).

Resources