PUT Request parse error - javascript

I have a website where a user stores resources and makes articles about them. At this time, i'm building the comments section where users can make comments in the articles. I have a put request which is triggered from controller which sends the id of the article and the comment.
but i receive the following error,
SyntaxError: Unexpected token 1
at parse (/home/themis/webappionio/node_modules/body-parser/lib/types/json.js:83:15)
at /home/themis/webappionio/node_modules/body-parser/lib/read.js:116:18
at invokeCallback (/home/themis/webappionio/node_modules/raw-body/index.js:262:16)
at done (/home/themis/webappionio/node_modules/raw-body/index.js:251:7)
at IncomingMessage.onEnd (/home/themis/webappionio/node_modules/raw-body/index.js:308:7)
at emitNone (events.js:67:13)
at IncomingMessage.emit (events.js:166:7)
at endReadableNT (_stream_readable.js:905:12)
at doNTCallback2 (node.js:441:9)
at process._tickCallback (node.js:355:17)
here is my server.js:
//defining Articles Model
var ArticleSchema = mongoose.Schema({
_creatorname: String,
title : String,
body : String,
resource: String,
published : String,
comments: [{
_commentorname: String,
content : String,
date : String
}]
});
var Articles = mongoose.model("Articles", ArticleSchema);
//pushing comment into the specific article
app.put("/home/:id", function(req,res){
var _commentorname = req.user.username;
var content = req.body.comment;
var date = moment().tz("Europe/Athens").format("DD/MM/YY HH:mm");
Articles.findByIdAndUpdate(
id,
{$push: {"comments" : {_commentorname: _commentorname, content: content, date: date}}},
{safe: true, upsert: true, new : true},
function(err, article) {
console.log(err);
}
);
});
My controller :
$scope.addComment = function(id, comment) {
console.log(id);
console.log(comment);
$http.put("/home/" + id, comment)
.success(function(response){
$scope.all();
});
};
and my html form:
<div class="panel-footer">
<input type="text" id="userComment" ng-model="comment" class="form-control input-sm chat-input" placeholder="Write your message here..." />
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" ng-click="addComment(article._id, comment)"><span class="glyphicon glyphicon-comment"></span> Add Comment</button>
</span>
</div>
Here is my final server.js
app.put("/home/:id", function(req,res){
var id = req.params.id;
Articles.findByIdAndUpdate(
id,
{$push: {"comments" : {_commentorname: req.user.username, content:req.body.comment}}},
{safe: true, upsert: true, new : true},
function (err, results) {
if (err)
{
res.send("there was a problem updating the information: " + err);
}
else {
res.format({
json: function() {
res.json(results);
}
});
}
}
);
});

The problem is that comment here is not actually being sent as an Object but just as a "string". So you need to structure the Object instead.
So correct the angular controller code:
$scope.addComment = function(id, comment) {
console.log(id);
console.log(comment);
$http.put("/home/" + id, { "comment": comment})
.success(function(response){
$scope.all();
});
};

New Answer:
Actually it looks like that you are submitting in the Angular controller the comment variable in a "raw" way instead of sending it as JSON, you need to change it to the
$scope.addComment = function(id, comment) {
console.log(id);
console.log(comment);
$http.put("/home/" + id, {comment: comment})
.success(function(response){
$scope.all();
});
};
Old Answer:
I think it throws the error because you format the date to the unusual format "DD/MM/YY HH:mm", if you would use native JS object it would work, e.g.
var date = moment().tz("Europe/Athens").toDate()

Related

MethodOverride PUT not working

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.

Delete item from nested array in Schema using moongoose

I need help with removing this item from nested array. I tried used $http.delete but this method deleted whole ObjectID from database, and second problem is that I can't connect the click on the "removing" button with backend code.
My code:
var product = new Schema({
title: String,
price: String,
description: [ObjectID]
});
Index.html
<form name="editProduct.descriptionForm" ng-submit="editProduct.updateDescription(newDescription, editProduct.descriptionForm.description.$valid)" novalidate>
<div ng-class="{ 'has-success':(editProduct.descriptionForm.description.$valid && !editProduct.descriptionForm.description.$pristine), 'has-error':(!editProduct.descriptionForm.description.$valid && !editProduct.descriptionForm.description.$pristine) || (!descriptionForm.description.$valid && descriptionForm.$submitted) }">
<div class="entry input-group" ng-repeat="item in newDescription track by $index">
<strong><input ng-disabled="editProduct.disabled" class="form-control" type="text" name="description" ng-model="newDescription[$index]" required></strong>
<span class="input-group-btn">
<a ng-click="editProduct.deleteDescription(item);" class="btn btn-remove btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</a>
</span>
</div>
</div>
<br>
<button ng-disabled="editProduct.disabled" class="btn btn-primary" type="submit">Save</button>
</form>
routes.js
router.put('/editProduct', function(req, res){
var editProduct = req.body._id;
var options = { multi: true };
Product.findOneAndUpdate({ _id: editProduct }, { $pull: { description: req.params.description }}, options, function(err, product){
if(err) throw err;
if(!product){
res.json({ success: false, message: 'Product no found' });
} else {
product.update(function(err){
if(err){
console.log(err);
} else {
res.json({ success: true, message: 'Description removed!'})
}
});
};
});
});
I also tried the following approach:
Product.findOne({'_id' : product.id}, function(err, me){
for(var i=0; i<=me.description.length; i++){
if (String(me.description[i])==String(uid)){
me.description.remove(uid);
me.save();
}
}
});
I think, the biggest problem is that I don't how to connect this function to the button.
Please try console.log(req.params.description) Before the Mongoose update query and check if the output is indeed a valid ObjectId.
If the console output is not showing the valid uid, then the problem is in the angular code. Most probably in editProduct.deleteDescription(item) function. Check if you are making Http Request by passing the correct Description Id as the parameter. Thats probably something like item.descriptionId or item.id. Debug thoroughly.

Passing URL parameter to Rest Method through Angular $HTTP

I am having trouble sending URL parameters to a rest method through a angular optimized html page.
My rest method:
router.get("/url/id/:urlid",function(req,res){
var query = "SELECT urlID AS libraryid, "
+ "URL AS libraryitem "
+ "FROM ?? "
+ "WHERE active = 1 "
+ "AND ?? = ? "
whereClause = ['urls', 'urlid', req.params.urlid];
query = mysql.format(query,whereClause);
connection.query(query,function(err,rows){
if(err) {
console.log("Rest Call Error");
res.json({"Error" : true, "Message" : "Error executing MySQL query", "Query" : query});
} else {
console.log("Rest Call Success", rows);
res.json({"Error" : false, "Message" : "Displayed the url "+req.params.urlid, "Query" : query, "URLs" : rows});
}
});
I can call the rest method directly and receive the following results
{
"Error": false,
"Message": "Displayed the url 5",
"Query": "SELECT urlID AS libraryid, URL AS libraryitem FROM `urls` WHERE active = 1 AND `urlid` = '5' ",
"URLs": [
{
"libraryid": 5,
"libraryitem": "url"
}
]
}
The Controller
app.controller("UrlByIDController", function ($scope, $http) {
$http.get('/api/url/id/{{urlid}}')
.then(function(data) {
console.log("URl loading", data)
$scope.links = data['URLs'];
})
.catch(function(response) {
console.error('Loading URL error', response.status, response.data);
})
.finally(function() {
console.log("finally finished loading urls");
});
});
The html template
<div class="form-group">
<label for="txtURL" class="control-label col-xs-3">URL</label>
<div class="col-xs-3" ng-controller="UrlByIDController" >
<input type="text"
id="txtURL"
class="ng-valid ng-dirty"
ng-model="formData.txtURL"
value="{{links.libraryitem}}"
placeholder="URL of Ad" />
</div>
</div>
When I debug the page I don't get an error but the id value that is passed to the rest method is the phrase 'urlid'. I am sure it is something pretty basic I am missing.
You cannot access your urlid in your Angular Controller with "{{urlid}}". This syntax can only be used in your HTML Template.
I can't see in your Controller how you get your urlid value from. One possibility would be to access urlid in $scope. But you have to set it somewhere first:
$http.get('/api/url/id/' + $scope.urlid)

Meteor using namedContext to addInvalidKeys to an AutoForm form returning an error

I have the following SimpleSchema where I am trying to add custom validation to validate against entering duplicate customer name, yet whenever I try to save a new customer I get error:
Exception in delivering result of invoking
'adminCheckNewCustomerName': TypeError: Cannot read property
'namedContext' of null
can someone please tell me what I am doing wrong / missing here to validate the customer name against duplicate records? Thanks
schema.js:
AdminSection.schemas.customer = new SimpleSchema({
CustomerName: {
type: String,
label: "Customer Name",
unique: true,
custom: function() {
if (Meteor.isClient && this.isSet) {
Meteor.call("adminCheckNewCustomerName", this.value, function(error, result) {
if (result) {
Customer.simpleSchema().namedContext("newCustomerForm").addInvalidKeys([{
name: "CustomerName",
type: "notUnique"
}]);
}
});
}
}
}
});
UI.registerHelper('AdminSchemas', function() {
return AdminSection.schemas;
});
form.html:
{{#autoForm id="newCustomerForm" schema=AdminSchemas.customer validation="submit" type="method" meteormethod="adminNewCustomer"}}
{{>afQuickField name="CustomerName"}}
<button type="submit" class="btn btn-primary">Save Customer</button>
{{/autoForm}}
collections.js:
this.Customer = new Mongo.Collection("customers");
Check collection2 code for fetching the schema attached to a collection:
_.each([Mongo.Collection, LocalCollection], function (obj) {
obj.prototype.simpleSchema = function () {
var self = this;
return self._c2 ? self._c2._simpleSchema : null;
};
});
This cryptic homonym _c2 (one of two hard things in programming...) comes from attachSchema:
self._c2 = self._c2 || {};
//After having merged the schema with the previous one if necessary
self._c2._simpleSchema = ss;
Which means that you have forgotten to attachSchema or fiddled with the property of your collection.
To solve:
Customer.attachSchema(AdminSchemas.customer);
//Also unless this collection stores only one customer its variable name should be plural

Error copying req.body properties into Mongoose Model

First of all I have to say that I'm new in Angular and node technologies. So sorry for my ignorance.
I get this error when I try to save an Entity from edition view: 'Cast to ObjectId failed for value "[object Object]" at path "category"'.
Well, I've got these code:
HTML:
<form class="form-horizontal" data-ng-submit="update()" novalidate>
<fieldset>
<div class="form-group">
<label for="listaCat">Categoría:</label>
<select id="listaCat" class="form-control" data-ng-Fmodel="notification.category" data-ng-options="c.name for c in listaCategorias track by c._id">
</select>
</div>
<div class="form-group">
<label class="control-label" for="name">Descripción</label>
<div class="controls">
<input type="text" data-ng-model="notification.name" id="name" class="form-control" placeholder="Descripción" required>
</div>
</div>
<div class="form-group">
<input type="submit" value="Guardar" class="btn btn-default">
</div>
<div data-ng-show="error" class="text-danger">
<strong data-ng-bind="error"></strong>
</div>
</fieldset>
</form>`
Angular controller:
$scope.update = function() {
var notification = $scope.notification;
notification.$update(function() {
$location.path('notifications/' + notification._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
Server side controller:
var mongoose = require('mongoose'),
errorHandler = require('./errors.server.controller'),
Notification = mongoose.model('Notification'),
_ = require('lodash');
exports.update = function(req, res) {
var notification = req.notification;
notification = _.extend(notification , req.body);
notification.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(notification);
}
});
};
Mongoose Model:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var NotificationSchema = new Schema({
name: {
type: String,
default: '',
required: 'Rellena la notificación',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
category: {
type: Schema.ObjectId,
ref: 'Category'
}
});
mongoose.model('Notification', NotificationSchema);
var CategorySchema = new Schema({
name: {
type: String,
default: '',
required: 'Rellena la categoría',
trim: true
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Category', CategorySchema);
So, if I debug inside Server controller at update method with WebStorm, I can see that req.body comes with each attribute well formed, but after convert req.body into Notification Mongoose Model with:
notification = _.extend(notification , req.body);
the category attribute is not a Model but an ObjectId. It seems as lodash.extend is not working properly for complex attributes. I've tried many other ways of cloning the object but without success.
Finally I solved it, with this line inside the angular controller:
notification.category = $scope.notification.category._id;
notification.$update(function() {
Anyway, I think that this is not the right way. I guess there must be a way of copying the req.body properties into a mongoose model without doing it manually for the complex properties.
Thanks a lot in advance!
Since you are working on AngularJS and ExpressJS, i would suggest you to use $resource service which is exactly meant for interacting with the rest API.
**$resource** contains these default set of actions:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };
There is nice documentation available in the link that i shared above.
In your case:
i assume, http://localhost:300/notifications/:id, this might be your rest url where you want to perform update action.
You can create your custom services like:
var module = angular.module('myapp.services',['ngResource']);
module.factory('MyAppUpdateService',function($resource){
return $resource('notifications/:id',
{
id: '#id'
},
{
'update': { method:'PUT' }
}
);
});
Now inside your angular app controller you can inject this service as dependency and hence it will be available to perform update in that REST url.
angular.module('myapp',['ngResource','myapp.services']);
angular.module('myapp').controller('MeetupsController',['$scope','$resource','$state','$location','MeetupUpdateService','socket',
function($scope,$resource,$state,$location, MyAppUpdateService){
$scope.updateMeetup = function(){
$scope.updateService = new MyAppUpdateService();
$scope.updateService.name = $scope.notification.name;
.
.
.
$scope.updateService.$update({id:$scope.notification.category._id},function(result){
$location.path("/meetup/")
});
}
})]);
So this was just an example, if you want more comprehensive implementation. Look here, i am creating a MEAN seed of my own, and i am doing the same.
Any doubt please do ask.

Categories

Resources