How to do conditional includes of partials in hoganjs with expressjs? (using hogan-express module) - node.js

I'm using express 3.0.x with hogan-express as template engine to build a single page application.
I would like to add a partial that will contain information that will help me to develop / debug the application. (I am also working with angularjs)
Depending on a variable somewhere in my app, like "devMode = true" I'd like to include this particular partial and it won't be included if "devMode = false".
Here are my files
index.js (routes):
exports.index = function(req, res) {
res.locals = {
template_engine: 'HoganJS'
}
return res.render(
'index',
{
partials:
{
head: 'head', foot: 'foot'
}
}
);
};
exports.partials = function(req, res) {
res.render('partials/' + req.params.entity + '/' + req.params.name)
}
index.html:
[[> head]]
<div class="navbar fixed-top">
<div class="navbar-inner">
<a class="brand" href="/">My app</a>
<ul class="nav">
</ul>
</div>
</div>
<div class="container">
<div ng-view></div>
</div>
[[> foot]]
(I changed {{ }} to [[ ]] to resolve conflict with angularjs syntax)
I'd like to include something like [[>dev]] before [[> foot]] depending on a boolean somewhere in my app.
Thank you for any help:)

Related

How do i make the ejs variable work that i send from nodejs?

I am tring to get a variable that i send from nodejs to ejs to work. But for some reason it wont, i cant figure out why.
This is the index.js:
var newOne = "Yes"
router.get('/main', ensureAuthenticated, (req, res) =>
res.render('main', {
user: req.user,
newOneInView : newOne
})
)
And this is in the main.ejs file:
<%if (newOneInView == "Yes") { %>
document.getElementById("avatar").src = "/static/images/Apocaliptic1.png";
<% } %>
So what i am trying to achieve is that variable will be seen from the nodejs at the main.ejs page but some reason it wont change the image SRC. What am i doing wrong here?
In your template you need to make sure that you place the code for changing the src attribute in a script that is placed after the element (alternatively you can use a listener for the content to be loaded), e.g:
<body>
<img id="avatar" src="/some-other-path"/>
<script>
<% if (newOneInView === "Yes") { %>
document.getElementById("avatar").src = "/static/images/Apocaliptic1.png";
<% } %>
</script>
</body>

Send Data from Span in EJS to Server Nodejs

Using Nodejs, Express, EJS
I see a lot of 'Send Data from Server to Client' but not from Client to Server AND sending the data from a tag not from a form input.
I would like to send the content of a tag from my ejs page/client to my nodejs/server.
What I'm trying...
page.ejs
<div>
<form action="/brewery" method="GET">
<div class="form-group">
<input type="text" class="form-control"
placeholder="search brewery name"
name="search">
</div>
<input class="button" type="submit" value="Submit">
</form>
</div>
<div>
<ul>
<% searchBreweryList.forEach(function(searchBrewery){ %>
<div>
<li>
Brewery Name: <span><%= searchBrewery.brewery.brewery_name %></span>
Brewery ID: <span name="brewID" id="shareBreweryID"><%= searchBrewery.brewery.brewery_id %></span>
</li>
</div>
<% }) %>
</ul>
</div>
Then on my server side...
server.js
app.get('/brewery', async (req, res) => {
var searchBreweryFound = req.query.search;
var isIndie = req.params.brewID
//console.log(isIndie)
//console.log(searchBreweryFound)
try {
request("https://api.com/v4/search/brewery?access_token=abc123&limit=1&q=" + searchBreweryFound, function (error, response, body)
{
if (error) throw new Error(error);
const searchBrewery = JSON.parse(body);
const searchBreweryList = searchBrewery.response.brewery.items.map(item => item );
res.render('brewery.ejs', {searchBreweryList});
//console.log(searchBreweryList);
});
} catch(e) {
console.log("Something went wrong", e)
}
});
So the above Get call is just an example where I'm trying to take the result in the client side span that looks like <span name="brewID">. Then I'm trying to give that ID number to the server in the var seen as var isIndie = req.params.brewID.
But this does not seem to be a method that allows me to pass content from a span in client to server.
What approach should I be taking? Thanks!
It's not clear what you mean by "sending data from client to server". Standard method of sending data from client to server is using XMLHttpRequest (XHR) inside *.js file(s), but based on your code you want to redirect browser window to URL with some parameters. When browser hit your endpoint, for example /brewery, server will render *.ejs file and respond to browser with HTML code.
Redirecting browser with EJS
Below code is based on code you posted.
<div>
<ul>
<% searchBreweryList.forEach(function(searchBrewery){ %>
<div>
<li>
Brewery Name: <span>
<%= searchBrewery.brewery.brewery_name %>
</span>
Brewery ID: <span name="brewID" id="shareBreweryID">
<%= searchBrewery.brewery.brewery_id %>
</span>
<!-- Here we create link using parameter of brewery (version with param) -->
Go to brewery
<!-- Version with query param -->
Go to brewery
</li>
</div>
<% }) %>
</ul>
</div>
After clicking Go to brewery browser will hit /brewery endpoint with param brewery_id. I also noticed that in posted example var isIndie = req.params.brewID may not work.
Bonus: req.query vs req.params
Both req.query and req.params are used to get some informations from endpoint URL. However req.query and req.params are not the same.
Using req.query
For endpoint: /brewery?id=5&q=test
const id = req.query.id // 5
const q = req.query.q // 'test'
Using req.params
To use req params you must place param name somewhere in url of express endpoint.
app.get('/brewery/:id', async (req, res) => {
var id = req.params.id
})
So to make your example with req.params working:
app.get('/brewery/:brewID', async (req, res) => {
var searchBreweryFound = req.query.search;
var isIndie = req.params.brewID
// Rest of your code
})

How do I store a variable for every route in Express.js?

So I'm building a simple authentication application and I'm using express-sessions to do this. For the UI, I need to display in the nav-bar a button for logging in, if the user hasn't done so already, and a button for logging out if they are already logged in.
The problem is, I'm not sure how to store this state across all of my routes, without using the same code for each route. Currently I've got this on the index route, which works fine:
/* GET home page. */
router.get('/', function(req, res, next) {
var logged_in = false;
if (req.session.userId) {
logged_in = true;
}
res.render('general/index', { is_logged_in: logged_in});
});
And in the nav-bar I display the buttons dynamically like so:
<% if( is_logged_in){ %>
<li class="nav-item active">
<a class="nav-link" href="/users/logout">Logout<span class="sr-only">(current)</span></a>
</li>
<% } else { %>
<li class="nav-item active">
<a class="nav-link" href="/login">Login<span class="sr-only">(current)</span></a>
</li>
<% } %>
But the problem is, I have to use the same code for each route if I want this to work for the nav-bar, which goes against DRY coding practices. How do I display this button dynamically without having to repeat the same bit of code on each route, checking if a user session ID exists? Do I set a global variable? I'm new to Express so all help appreciated. Thanks
You can setup a middleware to set the login status and use the res.locals for the lifetime of the request.
function checkLoggedIn(req, res, next) {
var logged_in = false;
if (req.session.userId) {
res.locals.logged_in = true;
}
}
You can then mount it for all the routes or chain it for some routes:
// all routes after this middleware:
app.use(checkLoggedIn)
// chain it
app.get('/mypath', checkLoggedIn, (req, res) => { ... })
res.locals are available to view as well so you can do the following without passing during render.
// You can simply render
res.render('general/index');
// logged_in variable is available to view
<% if(logged_in){ %>

Unable to render error page in ejs using nodeJS

I want the class to be activated when the path === '/' else ''.I used ternary operator to activate the class. the class is in active state when the path is equal but when the path is not equal it is unable to render the error page that i given
<header class="main-header">
<nav class="main-header__nav">
<ul class="main-header__item-list">
<li class="main-header__item"><a class="<%= path === '/' ? 'active' : '' %>" href="/">Shop</a></li>
<li class="main-header__item"><a class="<%= path === '/admin/add-product' ? 'active' : '' %>" href="/admin/add-product">Add Product</a></li>
</ul>
</nav>
the code runs fine if it is equal to the path but if it is not equal that when i want to render a error page
check this image for error message
First, omit the .ejs in your include statements:
<%- include('includes/navigation') %>
<%- include('includes/end') %>
Next, on your app.js, you will need to pass the path as context to the view:
app.get('/', function(req, res) {
const path = '/';
res.render('somePage', {path:path});
});
app.get('/admin/add-product', function(req, res) {
const path = '/admin/add-product';
res.render('somePage', {path:path});
});
Now, you shouldn't get the 'path is not defined' error.
Hope that helps!

MEAN correct way to refactor ejs express code

I've created a website with express and ejs, pulling JSON in from a file in a local file. I'd like to pass the data in from a mongo database and display with an Angular view. I have a good amount of knowledge in express, angular and mongo. Putting it all together and separating the express tasks from the angular tasks has me hung up a bit.
My app is working over in Heroku at http://healingcenter.herokuapp.com/services/ this is the page I'm unclear on how to separate the express and angular tasks.
It is currently set up in express, this was before I researched angular and the MEAN stack. below is the route config.
router.get('/services', function(req, res) {
var myServices = [];
var entireList = [];
entireList = appdata.services;
appdata.services.forEach(function(item) {
myServices = myServices.concat(item.title);
});
res.render('services', {
title: 'Services',
services: myServices,
list: entireList,
page: 'servicesList'
});
});
/* GET services detail page. */
router.get('/services/:servicesid', function(req, res) {
var myServices = [];
var entireList = [];
appdata.services.forEach(function(item){
if (item.shortname == req.params.servicesid){
entireList.push(item);
myServices = myServices.concat(item.title);
}
});
res.render('services', {
title: 'Services',
services: myServices,
list: entireList,
page: 'servicesDetail'
});
});
This is pulling in the same data.json file from the app.js file with this line of code.
app.locals.appdata = require('./data.json');
The page variable is the important part. An if else statement is customizing which data is brought in. That code is here:
<div class="services">
<% list.forEach(function(item){ %>
<article class="service group">
<% if (page!= 'servicesDetail') { %>
<h3><%= item.title %></h3>
<p><%- item.summary %></p>
more
<% }else{ %>
<a class="back" href="/services/#"><i class="fa fa-chevron-circle-left"></i> back</a>
<h3><%= item.title %></h3>
<p><%- item.description %></p>
<% } %>
</article>
<% }); %>
</div>

Resources