can't render in ejs template of node.js - node.js

I met a wield problem in node.js ejs template.
Here is the express code.
app.get('/course',function(req,res){
var locals = {};
locals.course = {
title: 'data.title',
city: 'data.city',
desc: 'data.desc',
id: 'data._id'
};
res.render('course_description',locals );
});
Here is the template code
<div >
<article>
<% if(locals.course) { %>
<div><% locals.course.title %></div>
<div><% locals.course.city %></div>
<div><% course.city %></div>
<div><% course.title %></div>
<% } %>
</article>
</div>
when res.render('course_description',locals ); is triggered, the local data should passed to the template, but for some unknown reason, it doesn't work for this example.
all I got is 4 empty
<div >
<article>
<div></div>
<div></div>
<div></div>
<div></div>
</article>
</div>
does anybody meet this wield problem before, I am so confused, I have done some working example before, but when I compare this with other working ones, I still can't find the reason.
Note, I am using the latest ejs and express

<% ... %> are for code constructions, not for output.
Try this:
<div>
<article>
<% if (locals.course) { %>
<div><%= locals.course.title %></div>
<div><%= locals.course.city %></div>
<div><%= course.city %></div>
<div><%= course.title %></div>
<% } %>
</article>
</div>

Related

Cannot read property 'name' of null error

I'm still a baby on web development. I am getting the following error, can
anyone help me?
Schema:
var campgroundSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
_id: String
});
var Campground = mongoose.model("Campground", campgroundSchema);
app.get("/campgrounds/:id",function(req , res){
Campground.findById(req.params.id, function(err, foundCampgrounds){
if(err){
console.log(err);
}else{
res.render("show", {campground: foundCampgrounds});
}
});
});
This is the index.ejs template:
<div class="row text-center" style="display:flex; flex-wrap:wrap">
<% campgrounds.forEach(function(campground){ %>
<div class="col-md-3 col-sm-6">
<div class="thumbnail">
<img src="<%= campground.image %>">
<div class="caption">
<h4> <%= campground.name %> </h4>
</div>
<p><a href="/campgrounds/ <%= campground._id %>"
class="btn btn-primary">More Info</a>
</p>
</div>
</div>
<% }) %>
</div>
show.ejs:
<%- include('partials/header')%>
<h1>this is a show template</h1>
<p><%= campground.name %></p>
<%- include('partials/footer')%>
TypeError:
Cannot read property 'name' of null
You should check if campground is defined at all - you can either do that in your nodejs-controller or in your template. Here's an example for ejs:
<%- include('partials/header')%>
<% if (campground) { %>
<h1>this is a show template</h1>
<p><%= campground.name %></p>
<% } else { %>
<h1>No camground data was found</h1>
<% } %>
<%- include('partials/footer')%>
On the index.ejs. Use a span to retrieve the _id from the
DB, as follows
<span> <%= campground._id %> </span>
Why? Because _id is a unique object and is auto-generated. No need to even
include it on the Schema unless you want to create it yourself on which case
you'll then amend the controller with a variable. I struggled with this but now
okay.

Error: Could not find matching close tag for "<%"

<% if (users.length > 0) { %>
<div class="grid">
<% for(user of users) { %>
<article class="card product-item">
<header class="card__header">
<h1 class="product__title">user.Username</h1>
</header>
<div class="card__actions">
<button class="btn">Go to profile</button>
</div>
</article>
<% } %>
</div>
<% } else { %>
<h3>No users are registered yet!</h3>
<% } %>
Inside the if statement > (greater than) sign is recognizing as closing tag. What should I do?
There are no syntax errors in the code supplied when tested using the following code (question code is contained in the template variable):
const ejs = require('ejs');
let template = `
<% if (users.length > 0) { %>
<div class="grid">
<% for(user of users) { %>
<article class="card product-item">
<header class="card__header">
<h1 class="product__title">user.Username</h1>
</header>
<div class="card__actions">
<button class="btn">Go to profile</button>
</div>
</article>
<% } %>
</div>
<% } else { %>
<h3>No users are registered yet!</h3>
<% } %>
`;
const renderData = {
users: [{
Username: 'test'
}]
};
const output = ejs.render(template, renderData);
console.log(output);
Console output:
<div class="grid">
<article class="card product-item">
<header class="card__header">
<h1 class="product__title">user.Username</h1>
</header>
<div class="card__actions">
<button class="btn">Go to profile</button>
</div>
</article>
</div>
However, as noted by #eol, user.Username should be wrapped in output tags.

forEach loop with if and else statements

So the title might not be the best description of my problem because I don't really know how to sum up the problem. I have a forEach loop for each event in my database and each one is classified as type = to either "trip", "ropes course", or "other". I have a section for each type of event, but I would like a way where if there are no events in the section I can not display the bannertron header and if there are no events in the whole database I can display different HTML. My code also seems very WET and I would love any suggestions on how to DRY up this page.
<% include partials/header %>
<div class="image-text">
<img src="../images/trip-photo.jpg" class="bannertron">
<div class="centered">Upcoming Trips</div>
</div>
<div class="container event">
<% events.forEach(function(event){ %>
<% if(event.type === "trip"){ %>
</br>
<h4><strong><%= event.title %></strong></h4>
<span><%= event.startdate %> - </span>
<span><%= event.enddate %></span>
<h6><strong>Location: </strong><%= event.location %></h6>
<p><%= event.description %></p>
<% if(currentUser && (currentUser.admin === true)){ %>
Edit
<form action="/calendar/<%= event._id %>?_method=DELETE" method="POST">
<button class="btn btn-danger">Delete</button>
</form>
<% } %>
<hr class="event-hr">
<% } %>
<% }); %>
</div>
<div class="image-text">
<img src="../images/climbing-photo.jpg" class="bannertron">
<div class="centered">Upcoming Climbing Days</div>
</div>
<div class="container event">
<% events.forEach(function(event){ %>
<% if(event.type === "ropescourse"){ %>
</br>
<h4><strong><%= event.title %></strong></h4>
<span><%= event.startdate %> - </span>
<span><%= event.enddate %></span>
<h6><strong>Location: </strong><%= event.location %></h6>
<p><%= event.description %></p>
<% if(currentUser && (currentUser.admin === true)){ %>
Edit
<form action="/calendar/<%= event._id %>?_method=DELETE" method="POST">
<button class="btn btn-danger">Delete</button>
</form>
<% } %>
<hr class="event-hr">
<% } %>
<% }); %>
</div>
<div class="image-text">
<img src="../images/other-photo.jpg" class="bannertron">
<div class="centered">Other Events</div>
</div>
<div class="container event">
<% events.forEach(function(event){ %>
<% if(event.type === "other"){ %>
<h4><strong><%= event.title %></strong></h4>
<span><%= event.startdate %> - </span>
<span><%= event.enddate %></span>
<h6><strong>Location: </strong><%= event.location %></h6>
<p><%= event.description %></p>
<% if(currentUser && (currentUser.admin === true)){ %>
Edit
<form action="/calendar/<%= event._id %>?_method=DELETE" method="POST">
<button class="btn btn-danger">Delete</button>
</form>
<% } %>
<hr class="event-hr">
</br>
<% } %>
<% }); %>
</div>
<% include partials/footer %>
Ideally, I would be able to loop through the events, check which type it is, put it in its respective area, and if there are none of a type, display some text like "no events scheduled" and if there are no events in total, display something else.
If this was me, I would split the events up into 3 different arrays in the node file, instead of sorting it all out inside of an ejs file. The Array.prototype.filter command would be useful for this. The nice thing about it is it returns a new array, with only items that return true for the function you pass in. It does not alter the original array, just passes a new one in. You can do something like
var trips = events.filter(function(event){
return event.type == "trip";
});
//do similar for "rope course", and for "other" you could do something like
return event.type != "trip" && event.type != "rope course"
// for the return statement.
You can do a
if(events.length == 0){
// show different html file
} else {
// show the html file with events, passing in the arrays
}
Make sure you pass all the arrays into the ejs file. For each array, you can do a similar
if(trips.length != 0){
// show banner and stuff
}
And do it for all three.
Hope this helps!

Nodejs ejs if else condition

Here i was trying for image to load, If image comes then it should show else default image. I have tried but no result
<% getdata.forEach((user) => { %>
<div class="col-md-4 col-sm-4">
<div class="service-box">
<% if ( typeof user.image == 'undefined' ) { %>
<img src="images/logo.png" class="" width='260' height='220'>
<% }else { %>
<img src="<%= user['image'] %>" class="">
<% } %>
</div>
</div>
<% }) %>
user.image may also be null or an empty string, in which case it doesn't pass your test for undefined.
Try this:
<% if (! user.image) { %>

How to convert handlebars to ejs

This is probably an easy question but I can't figure it out.
I want to change this handlebar code into ejs
{{#if hasErrors}}
<div class="alert alert-danger">
{{#each messages}}
<p>{{ this }}</p>
{{/each}}
</div>
{{/if}}
I tried but i'm getting syntax error
<%= if (Errors) {%>
<div class="alert alert-danger">
<%= each messages %>
<p><%= this%></p>
</div>
<% }%>
If your "hasError" variable is of type boolean, and your messages variable is an array of message strings;
<% if (hasErrors) {%>
<div class="alert alert-danger">
<% messages.forEach(function(message){ %>
<p><%= message %></p>
<% });%>
</div>
<% }%>

Resources