{ text: undefined,
done: false,
_id: 529e16025f5222dc36000002,
__v: 0 }
PUT /api/todos/529e16025f5222dc36000002 200 142ms - 68b
I keep getting this error when trying to do an update for my simple CRUD todo list. When I submit the update, the change doesn't appear on screen, although the put says it's a 200. Not sure what steps to take so that I don't get this "undefined" error and so I can have the update show up on screen.
EDIT: Included more code
This is the back-end node code:
app.put('/api/todos/:_id', function(req, res) {
Todo.findById(req.params._id, function(err, todos){
todos.text = req.body.text;
console.log(todos);
todos.save(function() {
if (!err) {
res.send(todos);
} else if (err) {
res.send(err);
}
Todo.find(function(err, todos) {
if (err)
res.send(err);
res.json(todos);
});
});
});
});
This is the Angular front-end code:
$scope.updateTodo = function(id) {
$scope.newItem = prompt("Please enter your new item:", "");
$http.put('/api/todos/' + id, {formData: $scope.newItem}).success(function(data) {
$scope.todos = data;
});
$http.get('/api/todos').success(function(data) {
$scope.todos = data;
});
};
I think it's because of this:
$http.put('/api/todos/' + id, { formData: $scope.newItem} )
^^^^^^^^
You're passing a single formData parameter with the request, yet in your Express code, you use this:
req.body.text
Either try this:
req.body.formData.text
Or don't use the formData parameter at all and pass $scope.newItem directly.
Besides that, your Express code is a bit messy: it might send back multiple responses and it doesn't check for errors on the save (as #PaulGray also pointed out).
Related
I'm using SailsJS as an API with Waterline connected to a MongoDB. I'm trying to put together an endpoint to edit existing DB entries but can't seem to get it to work and I'm hitting a wall as to why.
My route:
'post /edit/safety/:id': {
controller: 'SafetyController',
action: 'editSafety'
},
My controller function:
editSafety: function editSafety(req, res) {
var id = req.params.id;
Safety.findOneById(id).then((err, safety) => {
if (err) {
res.send(500, err);
return;
}
if (!safety) {
res.send(404, err);
return;
}
safety.title = req.body.title;
safety.description = req.body.description;
safety.status = req.body.status;
safety.save((err, updatedSafety) => {
if (err) {
re.send(500, err);
return;
}
res.send(200, updatedSafety);
});
});
},
Any push in the right direction would be greatly appreciated.
I don't recognize the Safety.findOneById method - is this something you have custom built? If not, then it is likely your problem.
Try swapping it for either:
Safety.findOne(id)
or
Safety.findOne({id: id})
Note that the returned object will be a model instance if the record exists, and undefined otherwise. If you decide to go with Safety.find instead then the returned value will be an array containing all models matching the query.
Looks like the main issue was transposing the response and err objects. It was successfully completing the query, but loading it into the err object which gets caught and a 500 error is thrown. So I changed that and simplified in a few other places.
editSafety: function editSafety(req, res) {
var id = req.params.id;
Safety.findOne(id).then((response, err) => {
var safety = response;
if (err) {
res.send(500, err);
return;
}
if (!response) {
res.send(404, err);
return;
}
safety.title = req.body.title;
safety.description = req.body.description;
safety.status = req.body.status;
Safety.update({
id: id
}, safety)
.then((result) => {
res.json(200, 'Ok!');
})
.catch((err) => {
sails.log.error('SafetyController.editSafety', err);
})
});
},
Hello I'm stuck in my first callback "selectArticleByTitle(title, callback)", the terminal send "Cannot read property 'id' of undefined". I don't know how to force the first callback to finish this and launch the others.
router.get('/article/:title', function(req, res){
dataBase.selectArticleByTitle(req.params.title, function(db_titleERR, db_titleResults){
console.log(db_titleResults);
dataBase.selectArticle(db_titleResults[0].id, function(db_resultsArticleERR, db_resultsArticle) {
//Get id of the previous article
dataBase.previousArticle(db_titleResults[0].id, function(db_previousIdERR, db_previousId){
//Get id of the next article
dataBase.nextArticle(db_titleResults[0].id, function(db_nextIdERR, db_nextId){
//Get lastArticle
dataBase.lastArticle(function(db_lastArticleERR, db_lastArticle) {
});
});
});
});
});
});
});
exports.selectArticleByTitle = function(title, callback){
connection.query('select * from article where title=?', [title], function(err, row){
if(err)
callback(err, null);
else{
if(row){
callback(null, row);
}
}
});
}
Here the log
console.log(db_titleResults);
[ RowDataPacket {
id: 7,
genre: 'Sciences',
picture: 'xw',
source: 'xswx',
title: 'zzazzaz',
meta: 'azazadsq',
inputDate: 2017-04-15T10:00:00.000Z,
visitor: 0 } ]
[]
Thank you in advance
If you want to stick with the original code then try the below...
The issue is that you are being returned one row. However you are trying to access the result as if there are many rows being returned in an array.
The below should at least get rid of your error. I would recommend to check the length of the results as well. if db_titleResults.length is defined then you know sql returned an array.
Instead of db_titleResults[0].id, you should use db_titleResults.id.
router.get('/article/:title', function(req, res){
dataBase.selectArticleByTitle(req.params.title, function(db_titleERR, db_titleResults){
console.log(db_titleResults);
dataBase.selectArticle(db_titleResults.id, function(db_resultsArticleERR, db_resultsArticle) {
//Get id of the previous article
dataBase.previousArticle(db_titleResults.id, function(db_previousIdERR, db_previousId){
//Get id of the next article
dataBase.nextArticle(db_titleResults.id, function(db_nextIdERR, db_nextId){
//Get lastArticle
dataBase.lastArticle(function(db_lastArticleERR, db_lastArticle) {
});
});
});
});
});
});
});
I am not sure what library you are using to connect to sql but can avoid nested call backs with an approach like below:
const sql = require('mssql')
sql.connect(config, err => {
// ... error checks
const request = new sql.Request()
request.stream = true // You can set streaming differently for each request
request.query('select * from article where title=?', [title])
request.on('row', row => {
// Emitted for each row in a recordset
dataBase.selectArticle(row.id, ...);
dataBase.previousArticle(row.id, ...);
dataBase.lastArticle(row.id, ...);
});
request.on('error', err => {
// May be emitted multiple times
});
});
This is my first attempt at deleting data in a MongoDB database. I'm loosely following this tutorial (just the delete part) to no avail, https://www.airpair.com/javascript/complete-expressjs-nodejs-mongodb-crud-skeleton. I just want to delete all the requested people who are in the requested country. All of my other requests work so I will just post the code that I know is not working, everything else is fine.
EDIT
The error I get in the log is "404 Not Found". When testing w/ Postman the response I get is, "Cannot DELETE /deletepeople/USA/John"
app.delete('deletepeople/:country/:name', function(req, res) {
var countryReq = req.params.country;
var nameReq = req.params.name;
peopleModel
.find({"country":countryReq}, function(err, country) {
country.find({"name": nameReq}, function (err, person) {
person.remove(function (err, person) {
if (err) {
console.log(err);
res.status(500).send();
}
return res.status(200).send();
})
})
})
});
});
country.find({"name": nameReq}, function (err, person) {
The above line is causing you an error, what are you searching in a returned document? Its just an document and not a collection.
You can use the id() method in embedded docs:
Look at the subdocuments [http://mongoosejs.com/docs/subdocs.html]
I can't figure out how I delete data in another MongoDB scheme when I create.
I'm running on mean.js stack.
exports.create = function(req, res) {
var sign = new Sign(req.body);
sign.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
sign.timesheets.forEach(function(entry) {
console.log(entry._id);
});
res.jsonp(sign);
}
});
};
Here I make a call to create a sign. Sign includes some strings and an array 'timesheets' with timesheet objects.
I also got a scheme for timesheets, I want to delete all timesheets objects that are included in my sign from timesheets scheme.
Here is my timesheets delete controller:
exports.delete = function(req, res) {
var timesheet = req.timesheet;
timesheet.remove(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(timesheet);
}
});
};
How do I call this from min sign controller, for each timesheet in sign?
Edit:
Route:
module.exports = function(app) {
var sign = require('../../app/controllers/sign.server.controller');
var timesheets = require('../../app/controllers/timesheets.server.controller');
app.route('/sign')
.post(sign.create, timesheets.deleteAll);
delete all
exports.deleteAll = function(req, res) {
var timesheet = req.timesheet;
timesheet.timesheets._id.forEach(function(entry) {
entry.remove(function(err) {
console.log(entry);
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(entry);
}
});
});
};
It runs and I can see id in the console, but it doesn't delete anything.
If you've implemented this as an array of TimesheetSchema documents inside each SignSchema document, then deleting the parent document would take everything that's part of it with it.
If you stored it as an array of ids referencing a document in another collection, then you'd have to go through those one by one and remove them as well. But I think it's better to go with the first approach if you don't need to do anything fancy. This was you can handle the removal easily, and it makes better sense semantically and performance-wise to retrieve everything you need to handle a "sign" in one go.
I have no problem retrieving all my models from the database and displaying them on page using this code:
index: function(req, res) {
Applicant.find(function(err, applicants) {
if (err) {
return console.log(err);
}else{
res.view({
apps: applicants
});
}
});
}
But, if I try to pull just one model and display it, my browser gets stuck on loading. This is the code that I use for pulling just one model:
display: function(req, res) {
Applicant.find().where({id: 2}).done(function(err, appl) {
if (err) {
return console.log('HAI');
}else{
res.view({
applicant: appl
});
}
});
}
Likely, your browser is stuck because an error happens when you're trying to find an Applicant, and your code doesn't return any response in this case. So browser waits for response forever.
Please try something like this
if (err) {
console.log('HAI');
return res.send(err, 500);
}
P.S. By the way, as of Sails v0.9, find() method will alwals return an array, even if only one record is found. If you want to find just one record by id, and expect single object in your view, you can use findOne() method.
.find() returns an array. You may be expecting a single applicant object.
Using appl[0] would solve this. Please note that Sails' Waterline ORM provides .findOne() for situations such as these. Here's more info on .findOne()
display: function(req, res) {
Applicant.find().where({id: 2}).done(function(err, appl) {
if (err) {
return console.log('HAI');
}else{
res.view({
applicant: appl[0]
});
}
});
}
Or better yet...
display: function(req, res) {
Applicant.findOne({id: 2}, function(err, appl) {
if (err) {
return console.log('HAI');
}else{
res.view({
applicant: appl
});
}
});
}