I keep encountering "ReferenceError: next is not defined" whenever i try to access /catalog/bookinstance/:id/delete. I Spent almost 2 hours trying to troubleshoot but to no avail :(
Any suggestions on which part went wrong?
catalog.js
/* GET request to delete BookInstance. */
router.get('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_get);
// POST request to delete BookInstance
router.post('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_post);
bookinstanceController.js
var BookInstance = require('../models/bookinstance');
var Book = require('../models/book');
var async = require('async');
// Display BookInstance delete form on GET
exports.bookinstance_delete_get = function(req, res, next) {
BookInstance.findById(req.params.id)
.populate('book')
.exec(function(err, bookinstance){
if(err){
return next(err);
}
res.render('bookinstance_delete', {title: 'Delete BookInstance', bookinstance: bookinstance})
});
};
// Handle BookInstance delete on POST
exports.bookinstance_delete_post = function(req, res, next) {
//req.checkBody('bookid', 'Book ID must exist').notEmpty();
BookInstance.findByIdAndRemove(req.body.id, function deleteBookInstance(err){
if(err){
return next(err);
}
res.redirect('/catalog/bookinstances');
});
};
bookinstance_delete.pug
h1= title
p #[strong Do you really want to delete this BookInstance?]
div(style="margin-left:20px")
p #[strong ID]: #{bookinstance._id}
p #[strong Title:]
a(href=bookinstance.book.url) #{bookinstance.book.title}
p #[strong Imprint:] #{bookinstance.imprint}
p #[strong Status:]
if bookinstance.status=='Available'
span.text-success #{bookinstance.status}
else if bookinstance.status=='Maintenance'
span.text-danger #{bookinstance.status}
else
span.text-warning #{bookinstance.status}
if bookinstance.status!='Available'
p #[strong Due back:] #{bookinstance.due_back_formatted}
form(method='POST' action='')
div.form-group
input#id.form-control(type='hidden',name='id', required='true', value=bookinstance._id )
button.btn.btn-primary(type='submit') Delete
bookinstance.js
var mongoose = require('mongoose');
var moment = require('moment');
var Schema = mongoose.Schema;
var BookInstanceSchema = Schema({
book: {type: Schema.ObjectId, ref: 'Book', required: true},
imprint: {type: String, required: true},
status: {type: String, required: true, enum: ['Available', 'Maintenance', 'Loaned', 'Reserved'], default: 'Maintenance'},
due_back: {type: Date, default: Date.now},
});
BookInstanceSchema
.virtual('url')
.get(function(){
return '/catalog/bookinstance/' + this._id;
});
BookInstanceSchema
.virtual('due_back_formatted')
.get(function(){
return moment(this.due_back).format('MMMM Do, YYYY');
});
module.exports = mongoose.model('BookInstance', BookInstanceSchema);
Related
I am using Node.js, Express and MethodOverride to try and have a form update only 1 part of a model (my user model).
User model:
var userSchema = new mongoose.Schema({
email: { type: String, unique: true, lowercase: true },
password: String,
profile: {
name: { type: String, default: 'Company Name' },
location: { type: String, default: 'Location' },
website: { type: String, default: 'Your Website' },
picture: { type: String, default: '' }
},
assetNumPre: { type: String, default: 'test' }, // this is the one I want to change
});
module.exports = mongoose.model('User', userSchema);
HTML form:
<form role="form-inline"action="/dashboard/settings/assetNumber?_method=PUT" method="POST">
<div class="col-md-3">
<div class="form-group">
<label for="prefix" class="control-label">Prefix for Asset Number</label>
<br>
<small>Any alphanumeric characters to a limit of 6</small>
<input type="text" class="form-control" id="prefix" name="prefix" placeholder="Prefix max 6 characters" maxlength="6" value="{{ prefix }}">
</div><!-- Prefix for Asset Number-->
<br>
<div class="box-footer">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
Then route:
app.put('/dashboard/settings/assetNumber',
setRender('dashboard/settings/assetNumbers'),
setRedirect({auth: '/login'}),
isAuthenticated,
dashboard.getDefault,
(req, res) => {
var prefix = req.body.prefix;
console.log(req.params);
User.findByIdAndUpdate({_id: req.params.user_id}, prefix, function(err, UpdatedUser) {
if (err) {
res.send(err);
}
console.log(UpdatedUser);
});
res.locals.prefix = req.user.assetNumPre;
});
One thing my route is missing is req.user.assetNumPre which is where I need to save it but I have no clue how to do this PUT request. Docs are not helping much either.
I got the route from a Stack Overflow example a few days ago and can't find the link to it. My app.js had method override working because I have done DELETE requests already. The model has the correct field and has a default test value that shows up in my show page.
You're calling this:
User.findByIdAndUpdate({_id: req.params.user_id}, prefix...
But prefix is only the value:
var prefix = req.body.prefix;
findByIdAndUpdate takes an Object, not a value, to update a specific field.
So try:
User.findByIdAndUpdate({_id: req.params.user_id}, { assetNumPre: prefix }...
Here is the fixed route:
app.put('/dashboard/settings/assetNumber',
setRedirect({auth: '/login', success: '/dashboard/settings/assetNumber', failure: '/dashboard/settings/assetNumber'}),
isAuthenticated,
(req, res) => {
User.findById(req.user.id, function(err, user) {
if (err) return (err);
user.assetNumPre = req.body.prefix || 'pre';
user.save(function(err) {
if (err) return (err);
req.flash('success', { msg: 'Asset Number Prefix updated.' });
res.redirect(req.redirect.success);
});
});
res.locals.prefix = req.user.assetNumPre;
});
So a few things changed that were not part of the issue. I figured out I need to just set the data inside the callback function. Then do a user.save.
I am trying to create a loop that will output the values into a table for me. What I have so far doesn't load anywhere on the rendered page. Nothing to show for it. I am not too sure how to do a loop with swig/twig so no idea what to include in this post. Please have a look at the code and if you need something else I will add it at request. My attempt at a loop:
{% for aps in aps %}
<tr>
<td>{{aps.name}}</td>
<td>{{aps.manufacturer}}</td>
<td>{{aps.model}}</td>
<td>{{aps.name}}</td>
<td>{{aps.notes}}</td>
</tr>
{% endfor %}
Model:
var accessPointsSchema = new Schema({
name: {String},
manufacturer: {type: String},
model: {type: String},
IPAdress: {type: String},
MACAdress: {type: String},
range: {type: Number()},
bands: {type: String},
channel: {type: Number},
dateBought: {type: Date},
PoE: {type: Boolean},
assetNumber: {type: Number},
warrantyExpiration: {type: Date},
location: {type: String},
notes: {type: String},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
email: String
}
});
Route:
// show model
app.get('/dashboard/it/model',
setRender('dashboard/it/model'),
setRedirect({auth: '/login'}),
isAuthenticated,
dashboard.getDefault,
(req, res) => {
console.log("Reached end/start thing");
AP.find({}, function(err, allAP){
console.log(allAP);
if(err){
console.log("Reached if");
console.log(err);
} else {
console.log("Reached else");
setRender('dashboard/it/model',{aps:allAP});
}
});
});
I'm going to attempt an answer based on the code you posted at https://github.com/joshk132/asset-management
Firstly, setRender doesn't seem to take a second argument. So instead try using something like this:
app.get('/dashboard/it/model',
setRender('dashboard/it/model'),
setRedirect({auth: '/login'}),
isAuthenticated,
(req, res, next) => { // Moved this before getDefault
console.log("Reached end/start thing");
AP.find({}, function(err, allAP) {
console.log(allAP);
if(err){
console.log("Reached if");
console.log(err);
next(err);
} else {
console.log("Reached else");
res.locals.aps = allAP; // Set the data in locals
next();
}
});
},
dashboard.getDefault
);
Importantly I've moved the database stuff before the call to dashboard.getDefault as getDefault calls res.render and the data all needs to be loaded before that happens.
You'll also need to address the next() call at the end of getDefault as there's nothing else to do.
The template would then be something like this:
{% for ap in aps %}
<tr>
<td>{{ap.name}}</td>
and so on.
I have an issue that I've been trying to figure out for some time now, and was hoping someone may be able to point me in the right direction.
My variable (error) that I'm passing along in the res.render{} object, is unusable within my layouts file. The issue is logging as a reference error.
If I take the ejs code out, my error properly logs to the terminal; I'm just unable to use it within my layout file.
Following is the layout.ejs code, in part.
<% for(var i = 0; i < errors.length - 1; i++){ %>
<li> <%= errors[i] %> </li>
<% } %>
and POST...
//POST route
app.post('/articles/add', function(req, res){
req.assert('title', 'Enter title').notEmpty();
req.assert('author', 'Enter author').notEmpty();
req.assert('body', 'Enter an article').notEmpty();
//get errors
req.getValidationResult().then(function(err){
if(err.isEmpty()){
console.log(err);
res.render('add_article',{
title: 'Add Article',
errors: err // <-
});
}
else {
let article = new Article();
article.title = req.body.title;
article.author = req.body.author;
article.body = req.body.body;
article.save(function(e){
if(e) {console.log(e)}
else{
req.flash('success', 'Article Added');
res.redirect('/');
}
});
}
});
Thanks for any help.
As per I see there are two bugs within your code. First, the if(err.isEmpty()), when err is empty then you are trying to send err!! And another is use of req.getValidationResult(), it will resolve with result object not an array. Below is the code that might help.
//POST route
app.post('/articles/add', function(req, res){
req.assert('title', 'Enter title').notEmpty();
req.assert('author', 'Enter author').notEmpty();
req.assert('body', 'Enter an article').notEmpty();
//get errors
req.getValidationResult().then(function(result){
if(!err.isEmpty()){
console.log(err);
res.render('add_article',{
title: 'Add Article',
errors: result.array() // <-
});
}
else {
let article = new Article();
article.title = req.body.title;
article.author = req.body.author;
article.body = req.body.body;
article.save(function(e){
if(e) {console.log(e)}
else{
req.flash('success', 'Article Added');
res.redirect('/');
}
});
}
});
And the result.array() will produce something like this:
[
{param: "email", msg: "required", value: "<received input>"},
{param: "email", msg: "valid email required", value: "<received input>"},
{param: "password", msg: "6 to 20 characters required", value: "<received input>"}
]
I am trying to assign some tags on post creation.
I have a Post model that looks like this:
var mongoose = require('mongoose');
var PostsSchema = {
title: String,
content: String,
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Users'
},
comments: [{
text: String,
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Users'
},
}],
tags: [String]
};
I am trying to bind the some checkboxes to the 'tags' array attribute in the Post.
This how my post router looks like:
///* Create post */
postRouter.route('/').post(function (req, res) {
mongoose.createConnection('localhost', 'CMS');
console.log(req.body);
var post = {
title: req.body.title,
content: req.body.content,
tags: req.body.tags
};
if (typeof req.body.title === "undefined" || typeof req.body.content === "undefined")
{
res.json({message:"Error"});
}else
{
var newPost = new Posts(post);
newPost.save(function (err, post) {
if (err) res.json({message:"Error"});
res.json(post);
});
}
});
My controller looks like:
$scope.createPost = function(post){
postService.createPost(post);
postService.getPosts()
.then(modelPosts);
}
And my view look like:
div(ng-controller='postController')
h2 Create Post
form
div.form-group
label(for='title') Title
input(type='text', class='form-control', id='title', name='title', placeholder='Title', ng-model='newpost.title', autofocus)
div.form-group
label(for='password') Content
input(type='text', class='form-control', id='content', name='content', placeholder='content', ng-model='newpost.content')
div(ng-controller='tagController')
h2 Tags
div( ng-model='Tags', ng-init='getTags()')
ul( ng-repeat='tag in Tags')
li
label
input(ng-model='newpost.tag',value='{{tag.name}}', type='checkbox', name='tag[]')
span {{tag.name}}
button( ng-click='createPost(newpost)', class='btn btn-small btn-primary') Create Post
I am not sure what is the problem with the binding my view to the model. Tags are rendered and checkboxes are created , but when i check one checkbox , all of them get checked.
input(ng-model='newpost.tag', ng-value-true='tag.name', ng-value-false='null' type='checkbox', name='tag[]')
Docs Input[checkbox]
I'm attempting to create a Mongo document then update the document form a form to have additional properties, one of which has an array of objects.
I'm able to save everything except objects to the address array.
The following code snippets show my current attempt to save an object to the address array. I feel like I'm missing a push or shift which I've tried and can't seem to get syntax correct.
Mongoose Schema:
var UserSchema = new mongoose.Schema({
username: { type: String, lowercase: true }
, password: { type: String }
, email: { type: String, lowercase: true }
, phone: { type: String }
, newsletter: Boolean
, created: { type: Date, default: Date.now }
, address: [{
nickname: { type: String }
, streetAddress: { type: String }
, streetAddress2: { type: String }
, state: { type: String }
, zip: { type: String }
}]
});
Model Methods:
First I create an account. The form only asks for username, email, password then redirects to the jade file where users can fill out the rest of the form.
module.exports = exports = function(){
//create account
this.createAndSave = function (req, res ) {
new User({
username: req.body.username
, password: req.body.password
, email: req.body.email
, phone: req.body.phone
, address: [{
nickname: req.body.nickname
, streetAddress: req.body.streetAddress
, streetAddress2: req.body.streetAddress2
, state: req.body.state
, zip: req.body.zip
}]
}).save(function (err, user){
if (err) throw err;
req.session.isLoggedIn = true;
req.session.user = user.username;
res.redirect('/account/' + user.username)
})
}
//update account
this.updateRequest = function (req, res) {
User.update({username: req.user.username}, {
username: req.body.username
, email: req.body.email
, phone: req.body.phone
, newsletter: req.body.newsletter
, address: [{
nickname: req.body.nickname
, streetAddress: req.body.streetAddress
, streetAddress2: req.body.streetAddress2
, state: req.body.state
, zip: req.body.zip
}]
}, function (err) {
res.redirect("/account/" + req.body.username);
});
}
Jade Template: (I'm sure this could be cleaner)
h1 Edit User
#{user}
form(method="POST", action="/account/#{user.username}")
input(type="hidden", name="_method", value="PUT")
.form-group
label(for="username") Name
input#name.form-control(type="text", name="username", value= user.username )
.form-group
label(for="email") Email
input#email.form-control(type="email", name="email", value= user.email )
.form-group
label Phone
input#phone.form-control(type="text", name="phone", value= user.phone )
.form-group
label Newsletter Opt In/Out
input#newsletter(type="checkbox", name="newsletter", checked=(true===false ? "checked" : undefined))
if(user.address.length > 0)
for (var i = 0; i < user.shippingAddresses.length; i++) {}>)
.form-group
label Street Address
input#address.form-control(type="text", name="streetAddress", value= user.shippingAddresses[i].streetAddress )
.form-group
label Address Continued
input#address2.form-control(type="text", name="streetAddress2", value= user.shippingAddresses[i].streetAddress2 )
.form-group
label Zip Code
input#zip.form-control(type="text", name="zip", value= user.shippingAddresses[i].zip )
else
.form-group
label Location Nick Name
input#address.form-control(type="text", name="nickname", value= )
.form-group
label Street Address
input#address.form-control(type="text", name="streetAddress", value= )
.form-group
label Address Cont.
input#address2.form-control(type="text", name="streetAddress2", value= )
.form-group
label State
input#state.form-control(type="text", name="state", value= )
.form-group
label Zip Code
input#zip.form-control(type="text", name="zip", value= )
button(type="submit") Update Account
Additionally there is another address only form which is why the address is an array.
Any direction would be very helpful as I may go unhinged at any moment. If you any further code let me know.
Something else to note, I'm not able to get any of the updated data from the update function to save to mongo.
Thanks!
Here is the solution I came up with. I find the document to update and push an object to the property that stores the array.
Example method:
this.addAddress = function (req, res) {
var newAddress = {
nickname: req.body.nickname,
streetAddress: req.body.streetAddress,
streetAddress2: req.body.streetAddress2,
state: req.body.state,
zip: req.body.zip
}
User.update({username: req.session.user}, { $push : {
address: newAddress
}}, {upsert: true}, function ( err ) {
if(err){
console.log(err);
}else{
console.log("Successfully added");
}
})
}