how to use app.locals inside app.get in express and parse - javascript

I am working on a parse application using express. I have an index file which shows the same information to the logged in users and public users except a login to public users and logout to logged in users. I am using app.locals to store a flag and logged-in user name but some how they are not getting stored.
My code for app.js is
// The homepage renders differently depending on whether user is logged in.
app.get('/', function(req, res) {
if(Parse.User.current()){
Parse.User.current().fetch().then(function(user) {
// Render the user profile information (e.g. email, phone, etc).
name = user.get('username');
});
app.locals({flag :true,name:name});
}else{
app.locals({flag:false, name:''});
}
// Render a public welcome page, with a link to the '/' endpoint.
var ProfessionalUsers = Parse.Object.extend("User");
var query = new Parse.Query(ProfessionalUsers);
query.limit(50);
query.equalTo("usertype", "Professional");
query.find().then(function(profs) {
res.render('index', {
title: "Popular Experts",
profs: profs,
});
});
});
The code I have written in index
<div class='navigation'>
<ul class='navigation-ul'>
<li><a href='/' class='search' id='searchLink' >Search</a></li>
<% if(flag){ %>
<li><a href='/dashboard' class='dashboard' id='dashboardLink' >Dashboard</a></li>
<% } %>
<li><a href='/howitworks' class='how-it-works' id='howItWorksLink'>How it Works</a></li>
<li><a href='/testimonials' class='testimonials' id='testimonialsLink' >Testimonials</a></li>
<li><a href='/faqs' class='faqs' id='faqsLink'>FAQs</a></li>
<% if(flag){ %>
<li><a href='/logout' class='logout' id='logoutLink'>Logout<span class='username'>(<%= name ? name : '' %>)</span></a></li>
<% }else{ %>
<li><a href='/login' class='login-signup' id='navLoginSignupLink'>Login/Signup</a></li>
<% } %>
</ul>
</div>
the code to show professionals
<p><%= title %></p>
<div class='professionals'>
<% for(var i=0;i<profs.length;i++) { %>
<div class='professional'>
<div class='picture-space' onclick = 'location.href = "/user/<%= profs[i].id %>"' style='cursor:pointer'>
<img src='images/default.jpg'/>
</div>
<div class='name-space'><%= profs[i].attributes.username %></div>
<div class='service-space'><%= profs[i].attributes.servicetype %></div>
<div class='linkedin-space'><a href='http://<%= profs[i].attributes.linkedin %>' target='_blank'>Linkedin Profile</a></div>
</div>
<% } %>
</div>
EDIT:
This is what I have done to fix this
// The homepage renders differently depending on whether user is logged in.
app.get('/', function(req, res) {
// Render a public welcome page, with a link to the '/' endpoint.
var ProfessionalUsers = Parse.Object.extend("User");
var query = new Parse.Query(ProfessionalUsers);
query.limit(50);
query.equalTo("usertype", "Professional");
query.find().then(function(profs) {
var user = Parse.User.current();
if(user){
user.fetch().then(function(user,error) {
res.render('index',{user:user.toJSON(),profs:profs,title:'Popular Experts'});
});
}else{
res.render('index', {
title: "Popular Experts",
profs: profs,
user:''
});
}
});
});

app.locals doesn't have access to the req, res objects. It is intended for non-dynamic data that doesn't change per request (like app-name, or something similar). I believe what you are after is res.locals (http://expressjs.com/api.html#res.locals)
I would suggest adding some middleware that does what you want.
You could load it just for your route. This will execute the middleware RIGHT before it executes the function you defined at that route:
function getUserInfo(req, res, next) {
var user_name = "adam"; //make some call here to get the user data
//make 'user_name' variable available in the view
res.locals.user_name = user_name;
next(); //go to the next 'middleware', which is the stuff you defined.
}
//add getUserInfo here as middleware that will run on the '/' route BEFORE your middleware runs. Yours will be executed when 'next()' is called from the middleware function.
app.get('/', getUserInfo, function(req, res) {

Related

How to add a button with an Update function using Node and Mongoose

I have created a mongoose db with events, each event is inside a bootstrap card. I am trying to figure out a way how can I redirect admin to a page where he can update the event-card and saved to my mongoose db.
The issue I have is that I already have a form for that card with a delete action and I need to be able to have another one. What I thought is to add a link which will redirect to an update_page.ejs where admin will can make changes to the form of that event and save them.
Code for admin.ejs page
<% events.forEach( function (event) { %>
<form class="form-events" action="/delete" method="post">
<div class="card col-lg-3" style="width: 18rem;">
<img class="card-img-top">
<div class="card-body">
<h5 class="card-title"><%= event.title %></h5>
<p class="card-text"><%= event.description %></p>
<p class="card-text"><%= event.date %> </p>
<p class="card-text"><%= event.capacity %></p>
Update
<button name="deleteBtn" value="<%=event._id%>" type="submit" class="btn btn-danger">Delete</button>
</div>
</div>
<% }); %>
</form>
Currently the update button redirects here:
where is basically a creation of an event.
A simple solution I thought is just to add another button near the create page like update.
So my first problem is that how can I after redirecting from my admin.ejs to create_page.ejs
have the from completed by the event pressed otherwise the form contents will be empty, and which app.() method I must use ( POST, PATCH ) and finally is it even possible to add 2 actions to one form?
app.js code
//Create new event route.
app.post("/create_event", function (req, res) {
const event = new Event({
title: req.body.ev_title,
description: req.body.ev_desc,
date: req.body.ev_date,
capacity: req.body.ev_cap,
});
event.save(function (err) {
if (err) {
console.log(err);
} else {
res.redirect("/admin");
}
});
});
// Delete an event
app.post("/delete", function (req, res) {
const deletedItemId = req.body.deleteBtn;
Event.findByIdAndDelete(deletedItemId, function (err) {
if (!err) {
console.log("Successfully deleted");
res.redirect("/admin");
} else {
console.log(err);
}
});
});
P.S my solution for the DELETE route is correct?
I am sorry for all the specifics, but I am totally new to this and have this project deadline coming up
googled all this method but the docs seemed a bit too technical right now for me.
You can simply add a another route to node application like
// Update an event.
app.post("/update/:id", function (req, res) {
const _id = req.params.id;
const event = new Event({
title: req.body.ev_title,
description: req.body.ev_desc,
date: req.body.ev_date,
capacity: req.body.ev_cap,
});
event.findOne({ _id }, '_id title description date capacity', function (err, data) {
if (err) {
console.log(err);
} else {
res.render('path to create_data.ejs', { event : data });
}
});
});
In the create_data.ejs file, fill all the form elements with value of the event like value="<%= event.title %>".
Note : If you're making above changes in create_data.ejs file, make sure to pass a blank event property in the create_event route as well like
// Create an event.
app.post("/create", function (req, res) {
res.render('path to create_data.ejs', { event : {});
});
Now,
Add a condition on create button in create_event.ejs file like
<% if(_event.id){ %>
... Update button to save the updated event
<% }else{ %>
... Create button to create a new event
<% } %>
Finally, In your admin.ejs file change
Update
to
Update
Hope this answers your question.

Why is this app.locals function in a button not working on my EJS template?

I have this script agents.js as follows
var express = require('express');
var router = express.Router();
var app = express(); // is it wise to call express like this twice?
router.get('/', function(req, res, next) {
var query = "role=agent";
get('employees').then(function(data) {
res.render("agents", {
rows: result,
user: req.user
});
}, function(error) {
res.send(JSON.stringify(error));
});
});
/// how can I expose this function to the application properly?
app.locals.add2Users = function(item) {
console.log("ADDING SOMEONE");
api.create(item, 'employees').then(function(data) {
console.log("Nice");
}, function(error) {
console.log("Error");
});
};
module.exports = router;
And a simple template agents.ejs
<% for(var i=0; i < rows.length; i++) { %>
<tr>
<td>
<%= rows[i].name %>
</td>
<td>
<%= rows[i].email %>
</td>
<td>
<% if (rows[i].toAdd) { %>
<button type="button" class="btn btn-info btn-outline btn-circle btn-lg m-r-5" onClick="add2Users(rows[i])">
<i class="ti-magnet"></i>
</button>
<% } %>
</td>
</tr>
<% } %>
The goal is to create a user on some back end database when the button on the template is clicked, by calling the add2Users function. I read that you can expose a function on an EJS template by adding it to app.locals, however I am getting the error add2Users is not defined. What am I doing wrong and what is the best way to expose a script function on an EJS template without going against best practices so to speak?
Rather than using app.locals, I ended up creating an endpoint /addUser/{param} and calling the endpoint from the client on click of the button.

Passing MongoDB Data into .ejs-Template with Node.js Express

I think i clicked myself through thousands of tutorials but i'm still stucked at this point: I want to render all the data, which my express-app is writing into mongodb at its start, into embedded javascript. I would like to have a simple table which is showing all the data from mongodb. It shall also always get the actualized Data when calling the route.
My first idea was, to save the data in an array. Pass it to the .ejs file. Create a table, iterate through my data-array and write it in. My problem is, that i can not write the data into an array after calling the find()-Function.
The model subscriber.js:
const mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
var subscriberSchema = mongoose.Schema({
nr: Number,
mailIdent: {
type: String,
unique: true
},
from: String,
emails: {
type: String,
default: ''
},
text: String,
uLink: String,
anwalt: Boolean,
create_date:{
type: Date,
default: Date.now
}
});
subscriberSchema.plugin(uniqueValidator);
var Subscriber = module.exports = mongoose.model('Subscriber', subscriberSchema);
I'm really new to the topic and it feels like i'm just messing around. Please help
//get Subscriber
/*module.exports.getSubscribers = Subscriber.find(function(err, subs){
if(err) return console.error(err);
console.log(subs);
});
*/
module.exports.subscriber = Subscriber;
module.exports.getSubscriberByID = function(_id, callback){
Subscriber.findById(_id, callback);
};
module.exports.getSubscribers = function(){
var subscribers = Subscriber.find({});
return subscribers;
};
Then i want to pass it with my app.js to the index.ejs:
app.get('/', function(req, res){
var subs = Subscriber.getSubscribers().toArray();
console.log(subs);
res.render('index',{subs: subs} );
});
I know, that my .ejs still seems a little simple. But so far it shall be just functional:
<!DOCTYPE html>
<html>
<head>
<link href="/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<% include partials/nav.ejs %>
<h1>Welcome to the Database</h1>
<p>You won't find more Information than here!</p>
<p>Table</p>
<table>
<colgroup span="5" class="columns"></colgroup>
<tr>
<th>Nr</th>
<th>Name</th>
<th>Mail</th>
<th>uLink</th>
<th>Anwalt</th>
</tr>
<% for (var i = 0; i<subs.length; i++) { %>
<tr>
<td><%= subs[i].nr</td>
<td><%= subs[i].name</td>
<td><%= subs[i].email</td>
<td><%= subs[i].uLink</td>
<td><%= subs[i].anwalt</td>
</tr>
<% } %>
</table>
</body>
</html>
The following is from mongoose docs:
Query#find([criteria], [callback])
When no callback is passed, the
query is not executed. When the query is executed, the result will be
an array of documents.
You can use a callback just Like you do with getSubscriberByID function, here is an example:
subscriber.js:
...
module.exports.getSubscribers = function(cb){
Subscriber.find({}, cb);
};
app.js
app.get('/', function(req, res){
Subscriber.getSubscribers( function (err, subs) {
if (err) throw err;
// else render result
res.render('index', { subs: subs} );
});
});
here is ur app.js code..
app.get('/', (req, res) => {
// db.collection('story').aggregate([
// { $lookup:
// {
// from: 'story_content',
// localField: 'ObjectId("5a322e1130cb6225a086f37d")',
// foreignField: "5a322e1130cb6225a086f37d",
// as: 'joinstorydata'
// }
// }
// ]).toArray(function(err, res) {
// if (err) throw err;
// console.log("********************************************************")
// console.log(res);
// final=res;
// });
db.collection('bid_placement').find().toArray((err, docs2) => {
if (err) return console.log(err)
// renders index.ejs
lnames2 = [...new Set(docs2.map(a => a.bid_location))]
lnames2.sort();
res.render('index.ejs', {
//story12 : docs1 ,
//story_content: final,
storylocation : lnames2
});
});
});
and here is ur html code
<select name="Courses" id="Courses">
<% for(var i=0; i<storylocation.length; i++) {%>
<option value="<%= storylocation[i]%>"> <%= storylocation[i]%> </option>
<% } %>
</select>
you can use it like <%= storylocation[i].abc%> .. put you desire data instead of abc on each column of table...
It was driving me mad and finally i found out. I did not closed the Javascript in the .ejs file. That was definetly the most stupid misstake ever

Display to client only if collection exists on mongoDB Node JS

I have this schema model defined on Mongoose:
var mongoose = require("mongoose");
var IngredientSchema = new mongoose.Schema({
name:String,
number:Number,
exist:Boolean,
photoName:String
})
module.exports = mongoose.model("Ingredient", IngredientSchema);
And I want to display on a web page a different result depending on whether there is an Ingredient already created on database or not.
Here's what I tried so far (but it doesn't work):
<!-- Check if inventory is empty or not, and display accordingly -->
<% if ( ! ingredients) { %>
<p>Add you first ingredient to the inventory !!</p>
<% } else { %>
<% ingredients.forEach(function(ingredient) { %>
...
...
And here's my route:
// Index route
app.get("/inventory", function(req, res) {
Ingredient.find({}, function(err, allIngredients) {
if (err) {
console.log(err);
} else {
res.render("inventory", { ingredients:allIngredients });
}
})
})
Thank you very much for your help.
Just check the length of ingredients array:
<!-- Check if inventory is empty or not, and display accordingly -->
<% if (!ingredients.length) { %>
<p>Add you first ingredient to the inventory !!</p>
<% } else { %>
<% ingredients.forEach(function(ingredient) { %>
...
...

Sails.js - Creating a view to edit a model

I have a simple model as follows:
module.exports = {
attributes: {
firstName: 'STRING',
lastName: 'STRING',
contact: 'STRING',
email: 'STRING'
}
};
I already have an index action that displays all the humans. This is the corresponding view:
<h1>List of all humans</h1>
<ul>
<% _.each(humans, function(model) { %>
<li><%= model.firstName %> /// <%= model.lastName %> /// <%= model.contact %> /// <%= model.email %> <button id="<%=model.firstName %>"type="button">Edit</button> </li>
<% }) %>
</ul>
What I want to accomplish is that every time someone clicks on the EDIT button, to display a view containing all the information of that specific model (localhost:1337/human/edit/:id). How can I write my controller? How can I tell my controller that I want THAT specific model to be displayed and route it properly?
Thank you!
You should point browser to localhost:1337/human/edit/:id url, where :id is your particular model's id. For example
<ul>
<% _.each(humans, function(model) { %>
<li><%= model.firstName %> <button id="<%=model.firstName %>" type="button">Edit</button>
</li>
<% }) %>
</ul>
This will automatically execute Human.edit controller with id param set to particular model's id. You don't have to write any custom routes, this is default behaviour.
Example of Human/edit controller action:
edit: function(req, res) {
Human.findById( req.param('id') )
.done(function(err, human) {
if (err) {
return res.send(err, 500);
} else {
if (human.length) {
res.json(human[0]);
} else {
res.send('Human not found', 500);
}
}
});
}
Here I return model encoded as json in response, for simplicity, but you can use your view.
In addition, firstName property is not the best value to use as buttons id attribute, because it should be unique.

Categories