using hidden fields in express js - javascript

Im trying to pass value of a hidden id field and use it to retriev records from mongodb and display it on profile page,after clicking "read more" on index page.This the index.ejs:
<% for(i=0; i<users.length; i++){%>
<div class="col-lg-3 center">
<div class="text-center">
<img class="img img-circle" src="<%= users[i].image %>" height="120px" width="120px" alt=""> <br>
<h4><b><%= users[i].fname %> <%= users[i].lname %></b></h4>
<ul class="list-inline social-buttons">
<li><i class="fa fa-linkedin"></i></li>
<li><i class="fa fa-github"></i></li>
<li><i class="fa fa-twitter"></i></li>
</ul>
<input type="hidden" name="id" value="<%= users[i]._id %>" >
<p><%=users[i].bio %>....Read More</p>
</div>
</div><!-- col-lg-3 -->
<% } %>
and here is profile.ejs:
<div class="medium-4 small-12 columns">
<h3> <%= users.fname %> <%= users.lname %></h3>
<p>Username: <%= users.username %></p>
<p>Email: <%= users.email %></p>
<p> Software Developer at <%= users.role %></p>
</div>
and express routes ,users.js.
app.get('/prof',function(req, res) {
var id=req.body.id;
var user = new User();
mongoose.model('User').findById(id,function(err, users){
console.log(users);
res.render('pages/profile',{users:users});
});
});
This gives me an error "Cannot read property 'username' of null.."
What am I missing?

You are doing a GET operation yet you are trying to send the id value through the POST parameters which are grabbed using req.body.variable_name.
In this case you don't need a hidden field as that needs a POST operation to send to the server. Try sending the id as a URL parameter which can be grabbed using req.param.id or req.query.id, for example
http://example.com/api/users?id=4&token=sdfa3&geo=us
or
http://example.com/api/users/4/sdfa3/us
If you want to get a query parameter ?id=57ada56845b8466147fc35b0, then use req.query
URL:
// GET /prof?id=57ada56845b8466147fc35b0
Markup:
<p><%=users[i].bio %>....Read More</p>
Route:
app.get('/prof', function(req, res) {
var id = req.query.id; // 57ada56845b8466147fc35b0
mongoose.model('User').findById(id, function(err, user){
console.log(user);
res.render('pages/profile', { users: user });
});
});
For the other parameter usage
URL:
// GET /prof/57ada56845b8466147fc35b0
use req.params.id
Markup:
<p><%=users[i].bio %>....Read More</p>
Route:
app.get('/prof/:id', function(req, res) {
var id = req.params.id; //57ada56845b8466147fc35b0
mongoose.model('User').findById(id, function(err, user){
console.log(user);
res.render('pages/profile', { users: user });
});
});

Related

Button press with foreach loop change button to other button Mongoose javascript

i want to press the edit button to change it to a save button and the delete button has te become cancel. when you press the button the text has to become a textarea so you can change it in the database.
this is the front end. know it only change the text of the button
<% itemsSmall.forEach(function(itemsSmall, index) {%>
<%if( String(image._id) === String(itemsSmall.imageId)){
%>
<div class="position-relative">
<div>
<p class="d-inline-block"><strong><%= itemsSmall.title %>:</strong> <%=itemsSmall.smallInformation %> </p>
</div>
<div style="display: none;" id="Test<%=String(itemsSmall.imageId)%>">
change text
</div>
<% if(image.userId == user.userId || user.admin > 2){ %>
<div class="col-12 col-md-6">
<button onclick="quoteAdd('{!!$product->id!!}', this)" id="inquireButton" class="btn btn-sm btn-warning float-right me-md-2">edit</button>
</div>
<div class="col-12 col-md-6">
<form action="/view/deleteSmall/<%= itemsSmall._id %>?_method=delete" method="POST">
<textarea name="imageId" id="imageId" hidden><%= image._id %></textarea>
<button class="btn btn-sm btn-danger float-right me-md-2" type="submit">delete</button>
</form>
<%}%>
</div>
</div>
<%}%>
<% }) %>
</div>
here is the peace of javascript for the button
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(document).ready(function(){
$('#myselection').on('change', function(){
var demovalue = $(this).val();
$("div.myDiv").hide();
$("#show"+demovalue).show();
});
});
function quoteAdd(productId, button) {
$(button).text('save');
}
</script>
and then a last we have the backend
//create the small information blocks
router.post("/uploadSmall", (req, res) => {
const id = req.params.id; //set the id from the page
//create the image
itemsSmall
.findById(id)
.then((result) => {
//set the image in een obj
var obj = {
title: req.body.Title,
smallInformation: req.body.smallInformation,
userId: req.auth.userId,
imageId: req.body.imageId,
};
//all the thing of the obj set to the model
itemsSmall.create(obj, (err, items) => {
if (err) {
console.log(err);
} else {
items.save(); //upload the model
res.redirect("/view/" + req.body.imageId);
}
});
})
.catch((err) => {
console.log(err);
});
});
router.post("/deleteSmall/:id", (req, res) => {
const id = req.params.id; //get the id of the text
//find the model in the database and delete it
itemsSmall.findByIdAndRemove(id, (err) => {
if (err) {
console.log(err);
return res.json({ success: false });
}
res.redirect("/view/" + req.body.imageId);
});
});
i found the anwser
you have to pass a value with the button and then change it.
here is the code
this is the html
<% itemsSmall.forEach(function(itemsSmall, index) {%>
<%if( String(image._id) === String(itemsSmall.imageId)){
%>
<div class="position-relative">
<div>
<p class="d-inline-block"><strong><%= itemsSmall.title %>:</strong> <%=itemsSmall.smallInformation %> </p>
</div>
<div style="display: none;" id="<%=itemsSmall._id%>">
your daddy
</div>
<% if(image.userId == user.userId || user.admin > 2){ %>
<div class="col-12 col-md-6">
<button onclick="quoteAdd('<%= itemsSmall._id %>', '{!!$product->id!!}', this)" value="<%= itemsSmall._id %>" id="inquireButton" class="btn btn-sm btn-warning float-right me-md-2">edit</button>
</div>
<div class="col-12 col-md-6">
<form action="/view/deleteSmall/<%= itemsSmall._id %>?_method=delete" method="POST">
<textarea name="imageId" id="imageId" hidden><%= image._id %></textarea>
<button class="btn btn-sm btn-danger float-right me-md-2" type="submit">delete</button>
</form>
<%}%>
</div>
</div>
<%}%>
<% }) %>
here is the javascript part
function quoteAdd(val, productId, button) {
var x = document.getElementById(val)
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
$(button).text(val);
}
i dont think it is the best way but it works

How to set two values to one html button

I'm working on a page where i'm rendering data from an api, where i make dynamic profile cards. And on clicking the button inside the card i'm calling an api through ajax. my problem is i need two values to pass to req.body to make the ajax success. I mananged the api call using one data using this code,
<div class="container" id="bb1">
<% locals.posts.rows.forEach(function (patient) { %>
<div class="patient-data">
<div >
<div style="padding-left: 100px"> <img src="<%= patient.dp %>" style="width: 45%;"> </div>
<br>
<div style="text-align: center;">
<h5> P.ID : <%= patient.p_id %></h5>
<p> Name : <%= patient.patient_name %></p>
</div>
<div style="padding-left: 110px;margin-bottom:20px ;">
<button type = "button" id="<%= patient.p_id %>" onclick="approve(this.id)" type="button" class="btn btn-info btn-sm" id="btn-success" style="background-color: #D1B147;"> View</button> </a></div>
</div>
</div>
<% }); %>
</div>
then inside my script;
<script type="text/javascript">
function approve(id) {
var p_id = id;
console.log(p_id);
var data = {};
data.p_id = p_id;
$.ajax({
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
dataType: 'json',
url: "http://localhost:5000/mData",
success: function(data) {
console.log(data);
localStorage.setItem('myData', JSON.stringify(data));
window.location.href = 'mastersessionhistory';
},
error: function(){
alert("Error")
console.log('error occured')
}
})
}
</script>
using this i was able to hit api and return values. i needed only the p_id to hit api. But now i have new key m_id to so my req.body should be {p_id,m_id}. How to include m_id on that bitton click so that i can call the api.
can i use this
<button type = "button" id="<%= patient.p_id, patient.m_id%>" onclick="approve(this.id)" type="button" class="btn btn-info btn-sm" id="btn-success" style="background-color: #D1B147;"> View</button> </a></div>

how can I activate the edit button? mongodb

I got this error
CastError: Cast to ObjectId failed for value "details5f9c3b069dc8723528c64cc8" at path "_id" for model "Book"
the edit and delete button are not activated.
Help me to figure it out please. this is /routes/books.js
and what else do I upload here?
// GET edit an existing Book
router.get('/:id', (req, res, next) => {
let id = req.params.id;
book.findById(id, (err, bookToEdit) => {
if(err) {
console.log(err);
//res.end(err);
} else {
//show the edit view
res.render('books/details', {title: 'Edit Book', books: bookToEdit})
}
});
});
// POST and update the document
router.post('/:id', (req, res, next) => {
let id = req.params.id
let updatedBook = book({
_id: id,
title: req.body.title,
description: req.body.description,
price: req.body.price,
author: req.body.author,
genre: req.body.genre
});
book.updateOne({_id: id}, updatedBook, (err) => {
if(err) {
console.log(err);
res.end(err);
} else {
// refresh
res.redirect('/books');
}
});
});
// GET - process the delete by user id
router.get('/delete/:id', (req, res, next) => {
let id = req.params.id;
book.remove({_id: id}, (err) => {
if(err) {
console.log(err);
res.end(err);
} else {
// refresh
res.redirect('/books');
}
});
});
This is /books/details.ejs
<div class="container">
<div class="row">
<form class="form" method="post">
<div class="form-group">
<label for="TitleTextField">Title</label>
<input type="text" class="form-control" id="TitleTextField"
placeholder="Book Title" name="title" value="<%= books.Title %>" required>
</div>
<div class="form-group">
<label for="AuthorTextField">Author</label>
<input type="text" class="form-control" id="AuthorTextField"
placeholder="Book Author" name="author" value="<%= books.Author %>" required>
</div>
<div class="form-group">
<label for="PriceTextField">Price</label>
<input type="text" class="form-control" id="PriceTextField"
placeholder="Book Price" name="price" value="<%= books.Price %>" required>
</div>
</div>
</div>
and this is /books/indexejs
<% include ../partials/header.ejs %>
<!-- MAIN CONTENT -->
<div class="container">
<div class="row">
<!--Add-->
<i class="fa fa-plus"></i> Add a book
<br>
<br>
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Title</th>
<th class="text-center">Author</th>
<th class ="col-4">Price</th>
<th class="text-center">EDIT</th>
<th class="text-center">DELETE</th>
</tr>
</thead>
<tbody>
<% for (let count = 0; count < books.length; count++) { %>
<tr>
<td><%= books[count].Title %></td>
<td class="text-center"><%= books[count].Author %></td>
<td class="text-center">$<%= books[count].Price %></td>
<!--EDIT-->
</td>
<td class="text-center">
<a href="/books/edit<%= books[count].id %>" class="btn btn-primary btn-sm">
<i class="fas fa-pencil-alt"></i> Edit</a>
</td>
<!--DELETE-->
<td class="text-center">
<a href="/books/delete<%= books[count].id %>" class="btn btn-danger btn-sm">
<i class="fas fa-trash-alt"></i> Delete</a></td>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
</div>
</div>
<% include ../partials/footer.ejs %>
this is /models/books.js
let mongoose = require('mongoose');
let Book = mongoose.Schema({
Title: String,
Description: String,
Price: Number,
Author: String,
Genre: String
},
{
collection: "books"
});
module.exports = mongoose.model('Book', Book);
hope these are helpful to fix the problems
You have an error that said that book.find and book.delete need an ObjectId as parameter. And details5f9c3b069dc8723528c64cc8 is not a valid ObjectId for Mongo.
Just read the error message !
Edition
Maybe you face this problem because you made a little mistake with resources, using same http POST to create and edit, giving the :id in path in both case.
If you have a POST / (no id in path) method to create books, letting mongodb generate ids, and have a PATCH (or PUT) /:id method to update those books, you probably will not have this kind of error anymore.
It will maybe sounds like stupid duplication but as your app will grow, you certainly will need to add some specific security rules.
Also, if I remember mongoose correctly, you're not supposed update the _id in second parameter for updateOne.
//no _id present in updatedBook
book.updateOne({_id: id}, updatedBook, (err) => { };
The default key of a document in MongoDB is _id who set an ObjectId in it.
ObjectId is a unique key who contained from some meaningful base on date and time (you can convert objectId to date).
You can read more about it here.
And your problem, it's really easy. You concat your ObjectId with details as you can see in the error.
details5f9c3b069dc8723528c64cc8 => 5f9c3b069dc8723528c64cc8

How to create self referencing MongoDB schema and post routes using nodejs?

I am trying to create parent-child like nested system where child has same schema as of parent.Below is my parent schema, here children refers to the parentSchema again,
var mongoose = require("mongoose");
var parentSchema = new mongoose.Schema({
name: String,
children:[
{
ref: this
}
],
});
module.exports = mongoose.model("Parent", parentSchema);
Routes looks like this
app.get("/", function(req, res){
Parent.find({}).populate("children").exec(function(err, allParents){
if(err){
console.log(err);
}else{
res.render("index",{parents: allParents});
}
});
});
app.post("/", function(req,res){
var name = req.body.name;
var desc = req.body.desc;
var newParent = {name: name, description: desc}
Parent.create(newParent, function(err, newlyCreate){
if(err){
console.log(err);
}else{
res.redirect("/");
}
});
});
app.post("/:id", function(req, res){
Parent.findById(req.params.id, function(err, parent){
if(err){
console.log(err);
res.redirect("/");
}else{
parent.children.push(req.body.child);
parent.save();
console.log(parent.children);
res.redirect("/");
}
});
});
The problem is when I send data from form to post route it prints it but after pushing it into parent.children and then printing parent.children is shows null. Where is the problem???
EJS page looks like below:-
<form action="/" method="POST">
<div class="form-group">
<input type="text" name="name" placeholder="Name">
</div>
<div class="form-group">
<input type="text" name="desc" placeholder="Description">
</div>
<div class="form-group">
<button class=btn-primary btn-block">Submit</button>
Go Back
</div>
</form>
<div class="row">
<% parents.forEach(function(module){%>
<ul class="list-group">
<li class="list-group-item" style="margin-bottom: 5%;">
<h2><%= module.name%></h2>
<%= module.description %>
<% console.log(module.children) %>
<%module.children.forEach(function(node){%>
<% console.log(node) %>
<%});%>
<div class="container">
<div class="row">
<div>
<form action="/<%= module._id %>" method="POST">
<div class="form-group">
<input type="text" name="name" placeholder="Name">
</div>
<div class="form-group">
<input type="text" name="desc" placeholder="Description">
</div>
<button>Submit</button>
</form>
</div>
</div>
</div>
</li>
</ul>
</div>
<% }); %>
</div>
Can anyone tell where is the problem in above code or can anyone suggest any other way to make this type of parent-child structure????
It seems that parent.save() is asynchronus. Maybe you can try this instead.
parent.save().then(()=>{
console.log(parent.children);
res.redirect("/");
});
or you can use async-await after putting async before function definition,
await parent.save();
console.log(parent.children);
res.redirect("/");
Please do write in comment if problem still persists.

SyntaxError: Unexpected token || in /var/www/html/views/components/show.ejs while compiling ejs

I'm attempting to build something similar to Colt Steele's YelpCamp project from his web Dev Bootcamp on Udemy. My project worked up until a refactor toward the end of the course using provided YouTube material. I get the following error message attempting to display anything from the database:
SyntaxError: Unexpected token || in /var/www/html/views/components/show.ejs while compiling ejs
If the above error is not helpful, you may want to try EJS-Lint:
https://github.com/RyanZim/EJS-Lint
Or, if you meant to create an async function, pass `async: true` as an option.
at new Function (<anonymous>)
at Template.compile (/var/www/html/node_modules/ejs/lib/ejs.js:626:12)
at Object.compile (/var/www/html/node_modules/ejs/lib/ejs.js:366:16)
at handleCache (/var/www/html/node_modules/ejs/lib/ejs.js:215:18)
at tryHandleCache (/var/www/html/node_modules/ejs/lib/ejs.js:254:16)
at View.exports.renderFile [as engine] (/var/www/html/node_modules/ejs/lib/ejs.js:459:10)
at View.render (/var/www/html/node_modules/express/lib/view.js:135:8)
at tryRender (/var/www/html/node_modules/express/lib/application.js:640:10)
at Function.render (/var/www/html/node_modules/express/lib/application.js:592:3)
at ServerResponse.render (/var/www/html/node_modules/express/lib/response.js:1012:7)
at /var/www/html/routes/components.js:84:17
at /var/www/html/node_modules/mongoose/lib/model.js:4834:16
at /var/www/html/node_modules/mongoose/lib/helpers/promiseOrCallback.js:24:16
at /var/www/html/node_modules/mongoose/lib/model.js:4857:21
at _hooks.execPost (/var/www/html/node_modules/mongoose/lib/query.js:4366:11)
at /var/www/html/node_modules/kareem/index.js:135:16
My /components/show (essentially campgrounds/show) code looks like this:
<%- include ("../partials/header") %>
<title><%=component.name%></title>
<%- include ("../partials/nav") %>
<div class="row">
<div class="col-md-3">
<p class="lead">PC Part Inventory</p>
<div class="list-group">
<li class="list-group-item active">Info 1</li>
<li class="list-group-item">Info 2</li>
<li class="list-group-item">Info 3</li>
</div>
</div>
<div class="col-md-9">
<div class="card mb-3">
<img class="card-img-top" src="<%= component.image %>" alt="<%= component.name %>">
<div class="card-body">
<p class="float-right">
This item costs $<%= component.price %>
</p>
<h5 class="card-title"><%= component.name %></h5>
<p>
<em>Submitted By <%= component.author.username %>, <%= moment(component.createdAt).fromNow() %></em>
</p>
<hr>
<p class="card-text"><%= component.description %></p>
<% if(currentUser && component.author.id.equals(currentUser._id) || currentUser && currentUser.isAdmin){ %>
<a class="btn btn-xs btn-warning" href="/components/<%= component._id %>/edit">Edit</a>
<form class="delete-form" action="/components/<%= component._id %>?_method=DELETE" method="post">
<button class="btn btn-xs btn-danger">Delete</button>
</form>
<% } %>
</div>
</div>
<div class="card">
<div class="card-body">
<a class="btn btn-success" href="/components/<%= component._id %>/comments/new">Add a Comment</a>
</div>
<hr>
<% component.comments.forEach(function(comment){ %>
<div class="row">
<div class="col-md-12">
<strong><%= comment.author.username %></strong>
<span class="pull-right"><%= moment(comment.createdAt).fromNow() %></span>
<%= comment.text %>
<% if(currentUser && comment.author.id.equals(currentUser._id)) || currentUser && currentUser.isAdmin){ %>
<a class="btn btn-xs btn-warning"
href="/components/<%= component._id %>/comments/<%= comment._id %>/edit">Edit</a>
<form class="delete-form" action="/components/<%= component._id %>/comments/<%= comment._id %>?_method=DELETE" method="post">
<input type="submit" class="btn btn-xs btn-danger" value="Delete">
</form>
</div>
<% } %>
</div>
</div>
<% }); %>
</div>
</div>
<%- include ("../partials/footer") %>
And my routes/components.js file looks like this:
var express = require("express");
var router = express.Router();
var Component = require("../models/component");
var Comment = require("../models/comment");
var middleware = require("../middleware");
var {isLoggedIn, checkComponentOwnership, checkCommentOwnership, isAdmin} = middleware;
// Defining escapeRegex for search feature
function escapeRegex(text) {
return text.replace
};
//INDEX- show inventory
router.get("/", function(req, res){
if (req.query.search && req.xhr) {
var regex = new RegExp(escapeRegex(req.query.search), 'gi');
//Getting Inventory
Component.find({name: regex}, function(err, allComponents){
if(err){
console.log(err);
} else {
res.status(200).json(allComponents);
}
});
} else {
// Get Items from DB
Component.find({}, function(err, allComponents){
if(err){
console.log(err);
} else {
if(req.xhr) {
res.json(allComponents);
}
else {
res.render("components/components", {components: allComponents, page: 'components'});
}
}
});
}
});
// CREATE- Add Components to DB
router.post("/", isLoggedIn, function(req, res){
//Get form data and add to array- add here with invSchema
var name = req.body.name;
var image = req.body.image;
var desc = req.body.description; //Add stuff from invSchema here
var author = {
id : req.user._id,
username: req.user.username
}
var cost = req.body.cost;
var newComponent = {name: name, image: image, cost: cost, description: desc, author:author};
// Create a new component
Component.create(newComponent, function(err, newlyAdded){
if(err){
console.log(err);
} else {
//redirect back to Inventory page
console.log(newlyAdded);
res.redirect("/components");
}
});
});
// NEW= Take to Inventory form
router.get("/new", isLoggedIn, function(req, res){
res.render("components/new");
});
//SHOW- shows info on specific component
router.get("/:id", function(req, res){
//find component by idea
Component.findById(req.params.id).populate("comments").exec(function(err, foundComponent){
if(err){
console.log(err);
req.flash('error', 'No components are listed under that name.');
return res.redirect('/components');
} else {
console.log(foundComponent)
//render show template with that component
res.render("components/show", {component: foundComponent});
}
});
});
//EDIT COMPONENT ROUTE
router.get("/:id/edit", checkComponentOwnership, isLoggedIn, function(req, res){
//Find the component
Component.findById(req.params.id, function(err, foundComponent){
if(err){
console.log(err);
req.flash('error', 'Unable to edit component')
} else{
res.render("components/edit", {component: foundComponent});
}
});
});
// UPDATE COMPONENT ROUTE
router.put("/:id", checkComponentOwnership, function(req, res){
var newData = {name: req.body.name, image: req.body.image, cost: req.body.cost, description: req.body.description};
Component.findByIdAndUpdate(req.params.id, {$set: newData}, function(err, component){
if(err){
req.flash("error", err.message)
res.redirect("back");
} else {
req.flash("success", "Component has been updated successfully")
res.redirect("/components/" + req.params.id);
}
});
});
// DESTROY Route
router.delete("/:id", checkComponentOwnership, isLoggedIn, function(req, res){
Comment.remove({
_id: {
$in: req.component.comments
}
}, function(err) {
if(err){
req.flash('error', err.message);
res.redirect('/');
} else{
req.component.remove(function(err) {
if(err){
req.flash('error', err.message);
res.redirect('/');
}
req.flash('error', 'Component Removed');
res.redirect('/components');
});
}
});
});
module.exports = router;
Any ideas what I could be doing wrong?
On line 45, there's an extra closing parenthesis after the comment.author.id.equals(currentUser._id) call.
<% if(currentUser && comment.author.id.equals(currentUser._id)) || currentUser && currentUser.isAdmin){ %>
<!-- ^^^^ -->
<a class="btn btn-xs btn-warning"
href="/components/<%= component._id %>/comments/<%= comment._id %>/edit">Edit</a>
<form class="delete-form" action="/components/<%= component._id %>/comments/<%= comment._id %>?_method=DELETE" method="post">
<input type="submit" class="btn btn-xs btn-danger" value="Delete">
</form>
</div>
<% } %>
The error message also suggests using ejs-lint to get more helpful error messages. I would recommend trying it out. In this case, it printed:
Unexpected token (45:81) in test.ejs

Categories