Convert form select box from .pug to .ejs - node.js

I'm trying to convert the below from pug to ejs. It's a select box of authors (from an associated collection) in a form to add a book to the db. It throws error "Cannot read property '_id' of undefined" pointing to the first option element when I add a new book (but I can update an existing book for some reason). And in the pug version it doesn't throw this error. Is my conversion right?
select#author.form-control(type='select', placeholder='Select author' name='author' required='true' )
- authors.sort(function(a, b) {let textA = a.family_name.toUpperCase(); let textB = b.family_name.toUpperCase(); return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;});
for author in authors
if book
option(value=author._id selected=(author._id.toString()==book.author._id.toString() ? 'selected' : false) ) #{author.name}
else
option(value=author._id) #{author.name}
My conversion:
<select class="form-control" id="author" type="select" placeholder="Select author" name="author" required="true">
<% authors.sort(function(a, b) {let textA = a.family_name.toUpperCase(); let textB = b.family_name.toUpperCase(); return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;}); %>
<% authors.forEach(function(author) { %>
<% if(typeof book !== 'undefined') { %>
<option value="<%= author._id %>" selected=<%= (author._id.toString() == book.author._id.toString()) ? 'selected' : 'false' %>><%= author.name %></option>
<% } else { %>
<option value="<% author._id %>"><%= author.name %></option>
<% } %>
<% }) %>
</select>

The conversion is right. Just a little mistake here <%= instead of <%
<option value="<%= author._id %>"><%= author.name %></option>
For any reason book.author is not present. Pug is catching undefined variables and continues rendering while ejs doesn't. So there is something wrong in your data.
Modify this line to prevent the error <% if(typeof book !== 'undefined' && 'author' in book) { %>
<select class="form-control" id="author" type="select" placeholder="Select author" name="author" required="true">
<% authors.sort(function(a, b) {let textA = a.family_name.toUpperCase(); let textB = b.family_name.toUpperCase(); return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;}); %>
<% authors.forEach(function(author) { %>
<% if(typeof book !== 'undefined' && 'author' in book) { %>
<option value="<%= author._id %>" selected=<%= (author._id.toString() == book.author._id.toString()) ? 'selected' : 'false' %>><%= author.name %></option>
<% } else { %>
<option value="<%= author._id %>"><%= author.name %></option>
<% } %>
<% }) %>
</select>

Related

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!

EJS unexpected Token "else"

I have a problem with syntax in ejs which isn't obvious to me:
<form class="dataForm" action="<%= template.actionPath %>" method="post">
<% for(var i in template.inputVar) { %>
<label><%= template.inputVar[i].labelName %></label>
<br>
<% if (template.inputVar[i].type == "option") { %>
<select name="<%= template.inputVar[i].name %>">
for(var j in template.inputVar[i].options) { %>
<option value="<%= template.inputVar[i].options[j] %>"><%= template.inputVar[i].options[j] %></option>
<% } %>
</select>
<% } else { %>
<input type="<%= template.inputVar[i].type %>" name="<%= template.inputVar[i].name %>">
<% } %>
<br><br>
<% } %>
I am rendering a webpage where a form is created. Now I want to add a feature that allowes me to have selections in my form.
Unfortunately ejs does not like my the "else" it says:
SyntaxError: Unexpected token else in C:\Users\etc... while compiling ejs
I did some research about this issue but I could not find something that might help me.
Your for line is missing the opening ejs script tag
for(var j in template.inputVar[i].options) { %>
to
<% for(var j in template.inputVar[i].options) { %>
Also, you should close your form tag

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) { %>

Passing an array to a EJS view, using Bookshelf.JS

My logic:
/* GET /events/list */
router.get('/events/list', function(req, res) {
new db.Tag({})
.fetchAll()
.then(function(tags) {
res.locals.title = "List of events";
res.locals.tags = tags;
res.render('events/list.ejs');
});
});
My view:
<% for (var tag in tags) { %>
<div class="checkbox">
<label>
<input type="checkbox" data-tag-id="<%= tag.tagId %>" />
<%= tag.name %>
</label>
</div>
<% } %>
What I'm getting:
[x] undefined
[x] undefined
[x] undefined
[x] undefined
What I should be getting:
[x] foo
[x] bar
[x] zort
[x] troz
I also tried passing
res.locals.tags = tags.toJSON();
and also
res.locals.tags = JSON.stringify(tags);
So.. how do I finally pass my collection to an EJS view?
I also logged (console.log(tags)) just after then(function(tags) and I'm getting the models (tags in this case) correctly.
I also tried tags.forEach in my EJS view but a native javascript array like this: [{tagId:1, name:"blah"}, {tagId:2, name"Foo"}] doesn't have "forEach" method implemented
In your template, use forEach (if available) or loop using the index instead.
server.js
res.locals.tags = tags.toJSON();
view.html (with [].forEach)
<% tags.forEach(function(tag) { %>
<div class="checkbox">
<label>
<input type="checkbox" data-tag-id="<%= tag.tagId %>" />
<%= tag.name %>
</label>
</div>
<% }) %>
view.html (with indices)
<% for (var i in tags) { %>
<div class="checkbox">
<label>
<input type="checkbox" data-tag-id="<%= tags[i].tagId %>" />
<%= tags[i].name %>
</label>
</div>
<% } %>
Here's an alternative to using Array.prototype.forEach. You give the Bookshelf collection to the view. Bookshelf.Collection has its own .forEach:
server.js
res.locals.tags = tags; // NOT .toJSON()
view.html
<% tags.forEach(function(tag) { %>
<div class="checkbox">
<label>
<input type="checkbox" data-tag-id="<%= tag.id %>" />
<%= tag.get('name') %>
</label>
</div>
<% }) %>

How do I create a dynamic dropdown menu in NodeJS?

Am experimenting with node Js. How do you create a dynamic dropdown menu?
Thanks.
<div class="control-group">
<%- form.label("state_or_province", false, {class: "control-label"}) %>
<div class="controls">
<!-- <%- form.input("state_or_province") %> -->
<select id="Facility_state_or_province" name="Facility[state_or_province]" size="1">
<% state_or_province_list.forEach(function (state_or_province_entry) { %>
<option value = "<%= state_or_province_entry.lookup_code %>" <%= (facility.state_or_province != null) && (facility.state_or_province == state_or_province_entry.lookup_code) ? 'selected = "selected"' : '' %>><%= state_or_province_entry.meaning %></option>
<% }); %>
</select>
</div>
</div>

Resources