I have this Angular7 app with NodeJS and MongoDB on the backend. I have tested out my put method with Postman and it works perfectly. The error lies in my Angular service component or possibly the component module that is using the service. No error messages are being displayed in the console. I have isolated it down to this--all the data is making it to the service, so the breakdown is between the service component and the Node api. Here's the method in my service.ts file:
updateSavings(pin: string, data){
const url = `api/accounts/${pin}`;
console.log(data);
return this._http.put(url, data, httpOptions)
.pipe(catchError(this.handleError)
);
}
Here is my Api.JS method that works fine with Postman:
router.put('/accounts/:pin', function(req, res, next) {
Accounts.findOneAndUpdate({pin: req.params.pin}, {savings:
req.body.savings}).then(function() {
//console.log(req.body.savings);
Accounts.findOne({pin:req.params.pin}).then(function(account){
//console.log(res.send(account))
})
})
})
Here is my component method that uses the services method:
depositSavings(data){
let y = this.accountsService.updateSavings(this.appComponent.rightPin,
data);
console.log(this.appComponent.rightPin);
return y;
}
}
Here is my template to show you what is going on there:
<input
type="text"
id="input"
[(ngModel)]="data"
[ngModelOptions]="{standalone: true}">
<br><br>
<button (click)="depositSavings(data)">Submit</button>
Any ideas what I have wrong? Thanks in advance guys.
You have to pass current _id as a first parameter and then whole object for update
router.put('/accounts/:pin', function(req, res, next) {
Accounts.findOneAndUpdate(req.params._id, {pin: req.params.pin, savings:
req.body.savings}).then(function() {
//console.log(req.body.savings);
Accounts.findOne({pin:req.params.pin}).then(function(account){
//console.log(res.send(account))
})
})
})
I handled the problem. As there were no error messages with this, it made it more challenging to figure this one out. What I was missing was this inside of my service method:
return this._http.put(url, {"savings": data}, httpOptions).subscribe(data =>
{console.log("PUT request successful ", data)})
In place of just data, you use {"savings": data}.
Related
I am using, sails.js to build a REST API. i want to use the first built in template of sails.js.
sails.js template choice
I am having issues with authentication. I can't use post man to sign in nor log in.
I searched a bit and I was able to get the _csrf token inside sails with
<form>
<input type="hidden" name="_csrf" value="<%= _csrf %>" />
</form>
but i couldn't find any route that will deliver me the token as a json so that i can access it form vue.
something like GET : localhost:1337/api/token
{ _csrf: 'ajg4JD(JGdajhLJALHDa' }
can someone help get me on track. i have been looking for a while now.
For frontend
In your frontend you can access the CSRF on the global object inserted by Sails - window.SAILS_LOCALS._csrf.
For testing
In your config/routes.js you will have to add this:
'GET /.temporary/csrf/token/for/tests': { action: 'security/grant-csrf-token' },
Do not let this go to production though. The recommended way for this is to only expose this route during automated tests. Here is some info about testing in Sails.js - https://sailsjs.com/documentation/concepts/testing - Here is my lifecycle.test.js - https://gist.github.com/Noitidart/63df651dc76812da6cb3bfe1ce4e9e0e - You see I expose this route only for my tests, so my production doesn't get this. It's not recommended to test your endpoints with Postman because those tests are ephemeral, your testing work is now gone after you are done. But if you write unit/integ tests, that work testing will stay forever.
If you are using Sails v1
// config/security.js
module.exports.security = {
csrf: true,
};
// config/routes.js
'GET /csrfToken': 'SomeController.grantCsrfToken',
// api/controllers/SomeController.js
module.exports = {
grantCsrfToken: function (req, res /*, next */) {
// Don't grant CSRF tokens over sockets.
if (req.isSocket) {
if (process.env.NODE_ENV === 'production') {
return res.notFound();
}
return res.badRequest(new Error('Cannot access CSRF token via socket request. Instead, send an HTTP request (i.e. XHR) to this endpoint.'));
}
// Send the CSRF token wrapped in an object.
return res.json({
_csrf: res.locals._csrf
});
},
}
// assets/js/some_filename.js
function send_some_post_request(extra_params) {
$.get("/csrfToken", function (data, jwres) {
if (jwres != 'success') { return false; }
msg = {
extra_params: extra_params,
_csrf: data._csrf
};
$.post("doStuff", msg, function(data, status){
});
});
}
I am able to complete the CRUD operations except update, my guess is the data flow into the updateTask function is not occurring correctly, what is the correction I need to make to fix the problem?
I sent in the data in the form of id and the title to the updateTodo function but it wont work.
this code is in the front end file.
updateTodo(id,title) {
axios.put(`http://localhost:4000/todos/${id}`,{title:this.todo.title}).then(() => {
this.getTodos();
this.isEditing = false;
});
}
and this is the code in the backend linked with axios.
router.route('/:id').put((req,res)=>{
Todo.findById(req.params.id,(err,todo)=>{
if(!todo){
res.send('Error fetching the todo.');
}else{
todo.title = req.body.title;
todo.save()
.then(todo=>{
res.json({'msg':'Todo updated successfully.'});
})
.catch(err=>{
res.send('the error in updating the task is ' + err);
})
}
})
})
The update functionality is working fine with the put method in the backend (checked via postman) but not working from the frontend.
updateTodo(todo) {
axios.put(`http://localhost:4000/todos/${todo._id}`,{title:todo.title}).then(() => {
this.getTodos();
this.isEditing = false;
});
}
sent in the whole todo instead of id and title separately, my bad for not checking it before posting.
In node 8.11.1, express 4.16.3 I installed
"express-messages" : "*",
"connect-flash" : "*",
"express-validator" : "*",
"express-session" : "*"
I have a page that gets all articles app.get('/', function(req, res){.... and also has a "New" button, for adding a new article. When hitting New, a pop-up Bootstrap form appears.
I want to check for empty form fields. The HTML form field that I check is
<input type="text" name="name" id="name" class="form-control" />
The form's action goes to
const { check, validationResult } = require('express-validator/check');
app.post('/add', [check('name').exists()],
function(req, res) {
const errors = validationResult(req);
console.log(errors.isEmpty());
if (!errors.isEmpty()) {
req.flash('err', 'errors'); //test
res.redirect('/');
}
else {
pool.connect(function(err, client, done) {
if (err) {
return console.log('db connect error '+ err);
}
client.query('insert into event (name) values($1)',
[req.body.name]);
done();
req.flash('success', 'saved');
res.redirect('/');
}); //pool connect
}//else
});
I am based in this. Whatever I do, the console.log(errors.isEmpty()); is always TRUE, so I end up saving to my DB empty fields. So, the express-validator does not catches errors ?
Also, I am not sure how to pass the errors back in the / route, so the errors can be rendered, this is why I just use req.flash('err', 'errors'); for now. Do I use req.flash like for the success part?
Please help me debug this.Thanks
express-validator maintainer here.
Regarding express-validator letting empty strings come through
check() will create a validator chain for something in the request named name.
It's not assertive of the location of the field, it could be req.query.name or req.body.name, for example.
If you want specifically req.body, then use the other chain creator body().
Then, even if you do have name in req.body, please note that check('name').exists() is not validating its content. It's simply checking it exists, as the name says.
If you want to check that it has some content, whatever that is, you can use check('name').not().isEmpty().
Regarding passing the errors to the redirected page
You can call either errors.array() or errors.mapped() to get the actual errors (please check the Validation Chain API for details).
I haven't used req.flash, so you should test if you can pass an JS object in there, or if you can only pass strings.
If you must use a string, then JSON.stringify/JSON.parse should be your friends to transport your errors.
I would like to enable pagination and I'm torn between client side and server side pagination. In the long term (more data) it is probably better to do server side pagination, but I haven't found a good tutorial on it.
I use Angular/Express/Mongo. I have the Boostrap UI in use, and would like to use their pagination directive for pagination. I have read some articels on how to kind of do it, but they are outdated and I cannot get it to work. http://fdietz.github.io/recipes-with-angular-js/common-user-interface-patterns/paginating-through-client-side-data.html
Could anybody help me get that example to work with Bootstrap UI for Angular?
If you have a set number of items per page, you could do it this way :
Define an angular service to query the data on your server.
.factory('YourPaginationService', ['$resource',
function($resource) {
return $resource('baseUrl/page/:pageNo', {
pageNo: '#pageNo'
});
}
]);
Call it via the angular controller. Don't forget to inject your service, either globally or in the controller.
$scope.paginationController = function($scope, YourPaginationService) {
$scope.currentPage = 1;
$scope.setPage = function (pageNo) {
$scope.currentPage = pageNo;
YourPaginationService.query({
pageNo: '$scope.currentPage'
});
};
};
On express 4 (if you have it), set up your route.
app.route('/articles/page/:pageNo')
.get(data.listWithPagination) //random function name
Then you need to wire that function with the desired Mongo request in your Node controller. If you have Mongoose, it works like this :
exports.listWithPagination = function(req, res) {
var pageLimit = x; //Your hardcoded page limit
var skipValue = req.params.pageNo*pageLimit;
YourModel.find() //Your Mongoose model here, if you use Mongoose.
.skip(skipValue)
.limit(pageLimit)
.exec(function(err, data) {
if (err) {
return res.send(400, {
message: getErrorMessage(err)
});
} else {
res.jsonp(data);
}
});
};
That's how I would do it on a typical MEAN stack. If you're working with different libraries/technologies, you might need to adapt a few things.
i'm fairly new to node.js so this could potentially a total noob question. Anyway. I discovered the mean.io Project. In the official article-example on Github, there is the following method in the article-controller.
exports.update = function(req, res) {
var article = req.article;
article = _.extend(article, req.body);
article.save(function(err) {
if (err) {
return res.jsonp(500, {
error: 'Cannot update the article'
});
}
res.jsonp(article);
});
};
With a corresponding route
module.exports = function(Articles, app, auth) {
app.route('/articles')
.get(articles.all)
.post(auth.requiresLogin, articles.create);
app.route('/articles/:articleId')
.get(articles.show)
.put(auth.requiresLogin, hasAuthorization, articles.update)
.delete(auth.requiresLogin, hasAuthorization, articles.destroy);
// Finish with setting up the articleId param
app.param('articleId', articles.article);
};
So I'm confused. When and where does the route pass the req/res parameters to the articles.update, or any other articles function? Is there some hidden mechanism in node/express/mean I've missed out?
Thanks in advance.
app.route('/articles/:articleId')
.get(articles.show);
This means express will invoke articles.show method with request and response as first two parameters when a GET request comes with matching path
.