if statement handlebars with passed 2 values - node.js

I'm making a site with handlebars and nodejs and I want to show a "message" (you can best compare them to tweets) only if the "message" is from a specific user.
For the if statement I used the following question asked on stackoverflow in the past: Logical operator in a handlebars.js {{#if}} conditional I'm passing through 2 variables: messages and username where username is a string and messages an array. I use message as |item| to get a specific place from the array. The username is stored in item.[0]. As I change the username in the value to "test" in line 3 of the hbs code so it would be {{#ifCond item.[0] "test"}} then it works, but not with the username passed through with the value.
Here's my handlebars code:
{{#if user}}
{{#each messages as |item|}}
{{#ifCond item.[0] username}}
<div class="card" style="width: 100%;">
<div class="card-body">
<h5 class="cardtitle">{{#key}}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{item.[0]}}</h6>
<h6 class="card-subtitle mb-2 text-muted">{{item.[2]}}</h6>
<p class="card-text">{{item.[1]}}</p>
</div>
</div>
<p></p>
{{else}}
<p>{{item.[0]}}</p>
{{/ifCond}}
{{/each}}
{{/if}}
The node.js code to load the page:
router.get('/users',loggedIn,messages,(req, res) => {
var user = res.user
var username = req.query.user
var message = res.message
if (user != undefined){
res.render("publicprofile", {user:user, username:username, messages:message, usernamestr:String(username)})
} else{
res.redirect("/")
}
});
and the handlebars helper:
hbs.registerHelper('ifCond', function(v1, v2, options) {
if(v1 === v2) {
return options.fn(this);
}
return options.inverse(this);
});

Related

how to get single value from input name field instead of array in NodeJS

I am trying to delete elements from the note list. when I try to match a single name to a list title, it shows an array of items.
i want to match
const input name ===day
and output should be "home" from input name field
but it show ["home","home","home","home"]
here is my delete form code:
<form action="/delete" method="POST">
<% for (let i=0; i<newListItems.length; i++) { %>
<div class="item">
<input type="checkbox" onChange="this.form.submit()" name="checkboxname" value="<%=newListItems[i]._id%>">
<p><%= newListItems[i].name %></p>
</div>
<input type="hidden" name="listName" value="<%= listTitle %>"></input>
<% } %>
</form>
app.js code:
app.post("/delete", function (req, res) {
const deleteItem = req.body.checkboxname
const listName = req.body.listName
console.log(listName)
if (listName === day) {
console.log("hello")
} else {
console.log("custome list value")
}
})
There is 4 hidden inputs rendered with same name listName.
So your request payload will be fulfilled with array of values from all of these inputs.
Move hidden input outside of PHP loop.
The point is to make one input with name='listName' instead of four

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
})

Iterate through a MongoDB object's data

I will start off with how my mongoDB data looks like:
_id : 5c5b450918cb2b121648ff7a
name : "dannondarko"
email : "dangilmail#gmail.com"
password : "$2a$10$3z5m1e9Pcfid72Q2GchCjeTD55/SsIxmtWr3I1ZiA.DX/KlpfTbdK"
date : 2019-02-06 20:35:21.973
__v : 0
posts : Array
0 : Object
note : "test for the user dannondarko"
date : "02/08/2019"
This is just a side project and most likely will never be live so don't worry about the security of me posting this data! As for how I am procession the code in my server code:
app.get('/:username', (req, res) => {
username = req.params.username.toLowerCase();
const collection = req.app.locals.collection;
collection.find({ name: username }).toArray(function (err, results) {
if (err) {
res.status(500).send("Error communicating with the DB.");
} else if (results.length > 0) {
console.log("Here are the results: " + results);
console.log({people: results});
res.status(200).render('profile', {posts: results, name: username});
} else {
next();
}
});
});
What I am doing with this code is say you head to the address bar '/dannondarko', it should find 'dannondarko' in the collection, which it does fine, and then the 'results' variable is the complete object that I posted above. What I am trying to do is just get the 'posts' data, such as the note and date.
The note and date is the only data I need, which will be sent to this .ejs file that should create a post (kind of like FB) that shows the users' notes and date of the post. Here is my .ejs file:
<h1 class="mt-4"><%= name %></h1>
<div class="container">
<br>
<% for(var i=0; i < posts.length; i++) { %>
<div class="container">
<label><%= posts[i].note %></label>
<div class="container">
<label><%= posts[i].date %></label>
</div>
</div>
<% } %>
</div>
I hope that's enough information. I believe my downfall is not knowing how to just extract the 'posts' array from MongoDB from a certain user and iterate through the objects and sending over the note and date to the .ejs.
The results is an array of documents and you render this array to ejs as posts. Now in your ejs file posts represent the array of documents, not the posts array. So if you want to loop through all results you should edit your code like this:
<% posts.forEach(post => { %>
<h1 class="mt-4"><%= post.name %></h1>
<div class="container">
<br>
<% post.posts.forEach(p => { %>
<div class="container">
<label><%= p.note %></label>
<div class="container">
<label><%= p.date %></label>
</div>
</div>
<% }) %>
</div>
<% }) %>
If i understand well your mongo model structure the above should help you.

How to work with dynamically loaded elements in YUI

I'm currently trying to integrate spring mvc app using YUI3. I was able to call Spring Controller with static href in jsp through YUI, but script is not getting invoked when trying to invoke dynamically generated href.
<script src="http://yui.yahooapis.com/3.14.1/build/yui/yui-min.js"></script>
<script>
YUI().use('io-form', 'json','datatable','node','tabview',function(Y) {
Y.all('#nav a').on('click', function (ev) {
ev.preventDefault();
//main.load(ev.target.get('href'), '#content');
var href = ev.target.get('href');
var url = href.substring(0,href.indexOf('#'));
var idw = href.substring(href.indexOf('#')+1,href.length);
Y.io(url, {
method: 'GET',
on: {
complete: function(id, response) {
answer = Y.JSON.parse(response.responseText);
Y.log(answer);
var main = Y.one('#'+idw);
var node = main.all('li');
if(node.size()===0){
Y.Object.each(answer, function(item, index){
main.append("<li id='"+item+"' class='api-list-item class'><a href='/YUI-2-Spring/getContactDetails/"+item+".html#"+item+"'>"+item+"</a></li>");
});
}
}
}
});
});
//To call controller on clickin of dynamic links
Y.all('#api-Types a').on('click', function (ev) {
ev.preventDefault();
//main.load(ev.target.get('href'), '#content');
var href = ev.target.get('href');
var neturl = href.substring(0,href.indexOf('#'));
var studId= href.substring(href.indexOf('#')+1,href.length);
Y.io(neturl, {
method: 'GET',
on: {
complete: function(id, response) {
answer = Y.JSON.parse(response.responseText);
Y.log(answer);
var main = Y.one('#api-everything');
var node = main.all('li');
if(node.size()===0){
Y.Object.each(answer, function(item, index){
main.append("<li id='"+item+"' class='module-class'><a href='/YUI-2-Spring/getPersonalDetails/"+item+"/"+contId+"'</a>"+item+"</li>");
});
}
}
}
});
});
});
</script>
The first script I'm using for calling controller on tabview selection .Based on that I'm creating a list of String with href inside <ul id="api-Types" class="apis modules"></ul> field. In the next script, I'm trying to invoke the generated links, but script is not getting executed.
<div class="yui3-u-1-4">
<div id="docs-sidebar" class="sidebar apidocs">
<div id="api-list">
<h2 class="off-left">APIs</h2>
<div id="api-tabview" class="yui3-tabview-content">
<ul id="nav" class="tabs">
<li class="yui3-tab yui3-widget yui3-tab-selected">Elements</li>
<li class="yui3-tab yui3-widget">Contact Details</li>
<li class="yui3-tab yui3-widget">All</li>
</ul>
<div id="yui3-tabview-panel">
<ul id="api-elements" class="apis classes">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
</ul>
<ul id="api-Types" class="apis modules">
<input type="search" id="api-filter" placeholder="Type to filter APIs"></ul>
<ul id="api-everything" class="apis search">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
<li class="message">
Begin typing in the search box above to see results.
</li>
</ul>
</div>
</div>
</div>
This is the dynamic list that got generated got from viewsource:
<ul id="api-Types" class="apis modules yui3-tab-panel yui3-tab-panel-selected" role="tabpanel" aria-labelledby="yui_3_14_1_1_1389513296688_62">
<input type="search" id="api-filter" placeholder="Type to filter APIs"><li class="api-list-item class">ABC</li><li id="BCD" class="api-list-item class">BCD</li><li id="CDE" class="api-list-item class">CDE</li><li id="DEF" class="api-list-item class">DEF</li><li id="EFG" class="api-list-item class">EFG</li><li id="FGH" class="api-list-item class">FGH</li></ul>
When I'm clicking on the links, instead of invoking the script, my controller is getting invoked through Dispatcher servlet.
Any help will be appreciated.
To bind events on dynamically added element on DOM you should use 'delegate' to bind event instead of 'on'. It will work.

Geddy - create new item

I am an absolute beginner in node.js and geddy. I've followed a few tutorials and now I try to write something similar for my purposes.
When I try to create a new item, though, I get the following message:
/arithmetic_problem_types/function%20(id)%20%7B%20%20%20%20%20%20options.id%20=%20id;%20%20%20%20%20%20return%20helpersBase.urlFor.action(options);%20%20%20%20%7D not found.
I have no idea where this could come from. I've looked through the code and found nothing.
Controller:
var ArithmeticProblemTypes = function () {
this.respondsWith =[ 'html', 'json', 'xml', 'js', 'txt'];
this.index = function (req, resp, params) {
var self = this;
geddy.model.ArithmeticProblemType.all(function (err, arithmetic_problem_types) {
self.respond({
params: params, arithmetic_problem_types: arithmetic_problem_types
});
});
};
this.add = function (req, resp, params) {
this.respond({
params: params
});
};
this.create = function (req, resp, params) {
var self = this, arithmetic_problem_type = geddy.model.ArithmeticProblemType.create({
name: '1', title: 'open', numberType: '1', numberRanges: '1', operators: '1', askedFor: '1', specialProblemCategory: '1', askedForNumDenomOrBoth: '1',
reducedFractions:'1', mixedFractions: '1'
});
arithmetic_problem_type.save(function (err, data) {
if (err) {
params.errors = err;
self.transfer('add');
} else {
self.redirect({
controller: self.name
});
}
});
};
....................................................................
};
exports.ArithmeticProblemTypes = ArithmeticProblemTypes;
add.html.ejs
<div class="hero-unit">
<%= partial('_form', {params: params}); %>
</div>
index.html.ejs
<div class="hero-unit">
<h2>Arithmetic Problem Types List</h2>
<%- linkTo('Create a new Aritmetic Problem Type', addArithmeticProblemTypePath, {class: 'btn pull-right'}) %>
</div>
<% if (arithmetic_problem_types && arithmetic_problem_types.length) { %>
<% for (var i in arithmetic_problem_types) { %>
<div class="row todo-item">
<div class="span8">
<h3><%- linkTo(arithmetic_problem_types[i].title, arithmeticProblemTypePath(arithmetic_problem_types[i].id)) %></h3>
</div>
<div class="span4"><h3><i class="icon-list-alt"></i><%= arithmetic_problem_types[i].status; %></h3></div>
</div>
<% } %>
<% } %>
How can I get rid of that message and make it work?
EDIT:
This is the beginning of the _form.html.ejs file:
<%
var isUpdate = params.action == 'edit'
, formTitle = isUpdate ? 'Update this Arithmetic Problem Type' : 'Create a new Arithmetic Problem Type'
, action = isUpdate ? arithmeticProblemTypePath(params.id) + '?_method=PUT' : arithmeticProblemTypePath
, deleteAction = isUpdate ? arithmeticProblemTypePath(params.id) + '?_method=DELETE' : ''
, btnText = isUpdate ? 'Update' : 'Add'
, nameValue = isUpdate ? arithmeticProblemTypePath.name : ''
, errors = params.errors;
%>
<form id="arithmetic-problem-type-form" class="form-horizontal" action="<%= action %>" method="POST">
....
</form>
EDIT2:
Inspecting the page where I should write the name of the item and click the add button, I've found this
<div class="hero-unit">
<form id="arithmetic-problem-type-form" class="form-horizontal" action="function (id) {
options.id = id;
return helpersBase.urlFor.action(options);
}" method="POST">
<fieldset>
<legend>Create a new Arithmetic Problem Type</legend>
<div class="control-group">
<label for="title" class="control-label">Title</label>
<div class="controls">
<input class="span6" name="name" placeholder="enter name" type="text">
</div>
</div>
<div class="form-actions">
<input class="btn btn-primary" type="submit" value="Add">
</div>
</fieldset>
</form>
</div>
Indeed the message comes from the action attribute of the form element, but how can I solve it?
The message is telling you that the requested URL could not be found. AKA 404
/arithmetic_problem_types/function%20(id)%20%7B%20%20%20%20%20%20options.id%20=%20id;%20%20%20%20%20%20return%20helpersBase.urlFor.action(options);%20%20%20%20%7D
is definitely not a nice looking url. So i'm assuming there's something wrong with your form's action attribute. If that's what happened when you validate the form.
If that's what happened when you click the link to "Create a new arithmetic problem type" then you should probably put parenthesis after addArithmeticProblemTypePath

Resources