Use angular to call multiple actions from Node.js - javascript

Please help, I'm unflushed in programming  . I created a route router.get('/statistics', routesCtrl.statistics) for a page where I want to display some statistics in some charts, using Angular.
I realized that I need to send some query results like, how many registrations are in db, how many of them have "this property", how many of them have “those properties” and so on, being something new for me. Until now in responses of the routes I sent only one statistic from the above list.
How should I send this info to Angular, should I create a literal object containing those statistics, packing them in the response and send it to the Angular? Or to send the entire json from db and parse it in Angular, but it seems to be a wrong idea also because I can't use then mongoose queries from Angular if it's true :) .
I don’t have any other idea and there probably are more professional ways. Thank you!

It is very simple, whenever you need data from server side, which is node.js in your case or anything it may be like PHP, asp.nrt etc you have to send http requests to server using angular $http (GET/POST) and along with required parameters as a json object or query string. At server end write some rest service type stuff to handle this and make use of send parmeters at server to query mongo and than pass collected data as a json object back to angular end. At angular you can parse this JSON, and angular have also scope to use JSON/Array directly in view using attribute ng-repeat and so on depends on your exact requirement.
Request in angular.js
var sendConfig = {
method : "POST",
url: "YOUR_URL",
data: {action : 'Test_Service'},
headers : {}
};
$http(sendConfig).success(function(response) {
console.log(response);
}).error(function(error) {
console.log(error);
});
Response In node.js
var server = http.createServer(function(req,res){
var webservice_actions_instance = new webservice_actions(req, res);
var service_response = {data : 'RESPONSE_HERE_AFTER_CERTAIN_ALGOS'};
res.writeHead(200, {'Content-Type': 'text/html',"Access-Control-Allow-Origin": "*","Access-Control-Allow-Headers":" X-Requested-With"});
res.write('Response Data '+ service_response);
res.end();
}).listen( 8080 );

Related

How to return multiple updates of a JSON using expressjs and nodejs

I have a server side task that takes some time to compute, and I'd like to periodically send updates to the client. I store and send the information as an object (via JSON), and it isn't an array where I can send data sequentially. Rather, I want to send some new information, and update others as the calculation continues.
From other posts on here I realize that:
response.json(object) is a nice and easy way to send an object json in one go, with headers set and everything. However, this - like response.send() - terminates the connection:
var app = express()
app.get('/', (request, response) => {
response.json( { hello:world } );
})
Alternatively, one could set the headers manually, and then use response.write with JSON.stringify
response.setHeader('Content-Type', 'application/json');
response.write(JSON.stringify({ hello:world } ));
response.end();
The above two methods work for sending an object in one go, but ideally what I'd like to do is send incremental updates to my object. E.g.
response.setHeader('Content-Type', 'application/json');
response.write( JSON.stringify( { hello:[world], foo:bar } ) );
// perform some operations
response.write( JSON.stringify( { hello:[world, anotherWorld], foo:cat } ) );
response.end()
However, what is happening on the clientside is:
After the first response.write, the client receives { hello:[world], foo:bar } but does not trigger my callback
After the second response.write, I can see the data received is { hello:[world], foo:bar }{ hello:[world, anotherWorld], foo:cat } still does not trigger my callback
My callback is only called after response.end(), and then I get an exception when trying to parse it as JSON, because it isn't a valid JSON anymore, but a bunch of JSONs stuck back to back with no comma or anything: Uncaught (in promise) SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data at line 1 column XXX of the JSON data.
Ideally my client callback would be triggered upon receiving each write, and it would remove that bit of data from the buffer so to speak, so the next incoming json would be standalone.
Is what I want to do possible? If so, how?
My fetch code btw:
fetch(url)
.then(response => response.json()) // parse the JSON from the server
.then(returnInfo => {
onReturn(returnInfo);
});
For your use-case, you can consider using WebSockets to deliver incremental updates to your UI. There are 3 stages of WebSockets connections. Connect, message and disconnect. One page load your front-end maintains persistent connection with backend. You can send first JSON data on connect and then when your backend has updates, send data in your message call back. I have written a blog post that implements WebSockets using Python and Javascript. However, you can implement similar logic using NodeJS
https://blog.zahidmak.com/create-standalone-websocket-server-using-tornado/

Deleting data from MongoDB using MEAN stack

MEAN stack newbie here. I'm having difficulty understanding how delete works in MEAN. I'm using this SO Q&A and tutorial as guides, but whenever I test it out I get an error saying the data can't be deleted. Can somebody tell me what I've been doing wrong?
Here are my codes:
Controller JS
$scope.deleteProduct = function (value, idx) {
var this_id = value._id;
// delete
$http.delete('/api/products/delete:' + this_id)
.success(function (data) {
console.log(data);
})
.error(function (data) {
console.log('Error: ' + data);
})
}
Node Server
app.delete('/api/products/delete:', productController.delete);
Server's "Controller"
module.exports.delete = function (req, res) {
Service.remove({
_id: req.params._id
}, function (err, service) {
if (err) {
res.send(err);
}
else {
res.json({message: "Delete successful."});
}
});
}
This is how I understood this. Is this correct?
Controller JS gets the id to be deleted and calls $http's delete request(?), using said ID and the /api/products/delete:.
Node Server sees that I called '/api/products/delete:' and passes the request to Server's Controller to complete the request.
Server's Controller deletes the data and returns status.
Where did I go wrong? Please help.
Also, I've been seeing some posts that say $resource works better than $http. Why?
Thank you.
I think you've got a couple things wrong here.
In Express in order to use params you need to have something in the route that can be replaced. i.e /api/:id express replaces the :id with whatever you pass in so if you send /api/1, request.params.id is 1
So first problem is your route is
app.delete('/api/products/delete:', productController.delete);
tha dosen't mean anything to Express. I think you want
app.delete('/api/products/:id', productController.delete);
now req.params.id should contain the parameter you send. Note im dropping the underscore here. you could use
app.delete('/api/products/:_id', productController.delete); and keep the underscore if you like.
Second mistake I think is your Angular code. you have the : in your call it should just be
$http.delete('/api/products/' + this_id)
Now you're sending the route with whatever Id you are trying to delete i.e
/api/products/1
Now Express gets that and can map it to /api/products/:id and replace the id and now your controller should work. barring any other issues.
Edit
I'm not very familiar with Angular but I think the reason people are saying to use $resource is it is easier. You can directly call the different HTTP verbs directly on the objects themselves objects like
product.update and product.delete rather than trying to craft the http calls yourself. I'm sure there is a lot more to it than that but its a feature that's built into Angular that can be leveraged. I think one of the catches is the URLs for the resources just have to be set up a specific way on the server but I believe there was a way to override them in Angular.

How should I display data from backend in Node.js + jade + angularJS + mongoose

I'm going to make web application (SPA) with:
Backend: Node.js (express)
Frontend: Jade + AngularJS
Database: Mongoose
I will send data (as a form) to backend in this way ExpressJS AngularJS POST (Check ANSWER)
It will be simple CRUD.
However i wondering how should I display data from backend?
For example:
I'll run application
var Partner = require('../model/partners');
router.get('/', function (req, res) {
Partner.find({}, function (err, partnerList) {
if (err) throw err;
res.render('campaign', {
partnerList: partnerList
});
});
});
And how should i display data (partnerList). Maybe in this way?
- each item in partnerList
= item.name
Or maybe there is another better way with angular to display data at view? I'm asking because later i'd like remove or update items from partnerList (CRUD operation). And it may be a problem because i will have to send item._id as a parameter to angular function?
For example if i will add button to remove record:
- each item in partnerList
= item.name
button(type='remove' ng-click="sub('#{item._id}')")
script.
app.controller('view1Ctrl', function($scope, $http) {
$scope.sub = function(id) {
$http.post('/',id).
success(function(data) {
console.log("posted successfully");
}).error(function(data) {
console.error("error in posting");
})
}
});
Probably it won't work correct
As said in previous coment, from my point of view I prefere to send the minimum required data from the backend to the client, but it depends of you infrastructure and you concurrent users.
Example 1:
You have a web app with +5K concurrent users, in this case is better handle all the huge stuff at frondend side or you will need to spend a lot of money in your backend hardware.
Practical case:
Users POST a new comment in a blog page. You sanitize the text string at the backend and put it at you preferred datastore... But JUST respond with a simple json like {"status": "ok"}. If the frond end recive this, modify the DOM with the text string that the client sent to the backend in the POST stage, but not send again all the HTML with this (for example) 500 characters comment.
If server responds with {"status":"error"}, modify the DOM to let the user know what's the problem about his comment (more specified json message {"status":"error", "data":"you comment is bigger than 500 chars"})
Problems:
You need extra frontend code to handle these situations in the client side. So this "maybe" will inpact on the user the 1st time that it visits your page.
Pros:
Less hardware costs
Overall less server response times.
More user interactive website modeling only certain parts of the DOM at any moment.
...
Example 2:
You have a simple page with low concurrent users. Then you choose. Let you backend to handle everything? Or keep working with json responses?
I always use the 1st example. Hope this helps in your question.
I think the preferred method would be to set up a second route from express to specifically render JSON, then use angular's $http method to get that data and use it in your controller. If you want to do it with a single route, you can pass the JSON data as a string to your view on the server-side, but it might get a little unruly.
// app.js
...
partnerList: JSON.stringify(partnerList);
...
// index.jade
div(ng-repeat="item in partnerList")
p {{ item.name }}
button(type='remove', ng-click="sub(item._id)")
...
script.
app.controller('view1Ctrl', function($scope, $http) {
$scope.partnerList = JSON.parse(#{partnerList});
...
EDIT To use the JSON string example, you would have to render using the Unbuffered Code syntax. But I'm not sure how you would do that inside a script. block. To instead go the route of serving JSON separately, change your server routes to this:
var Partner = require('../model/partners');
router.get('/', function (req, res) {
res.render('campaign');
});
router.get("/partner-list", function(req, res) {
Partner.find({}, function (err, partnerList) {
if (err) throw err;
res.json({ partnerList: partnerList });
});
});
Then your angular code will query that /partner-list path with $http.get().
script.
app.controller('view1Ctrl', function($scope, $http) {
$http.get("/partner-list").then(function(result) {
$scope.partnerList = result.data.partnerList;
});
...
});

How to pass request parameters back to Angular

I currently have an app which uses Express with Jade templates.
I'm building a new version of the app using Angular with client-side HTML.
I need access to certain request parameters in order to determine user permissions in my Angular code. My problem is that I don't know how to get ahold of these parameters in my Angular controllers/services.
Below is what currently occurs in Express with the Jade structure:
routes.js:
router.get('/player/:id',
playerRoute.show
);
player.js:
var show = function(req, res) {
res.render('player', {user: req.user});
};
...and now my new version's handler:
var player = function(req, res) {
//res.sendFile(path.join(__dirname, '../v2', 'index.html'));
res.json({user: req.user});
};
The correct user JSON is sent back to my client-side with the code above. When res.json is commented out and res.sendFile uncommented the correct HTML is rendered. My dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
After all that, your question just boils down to:
MY dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
You don't. The usual case is to just render the HTML along with the assets needed to render the initial app (hide everything, show a splash screen whatever). Further data (like getting your user) is handled by API calls to your server via Angular's HTTP facilities. That means they are separate. After that API call, your app determines what to render.
Otherwise, you could just render the data in the HTML as some global variable and have Angular pick it up from there. This is messy IMO, but doesn't require a separate API call to get the data.
copied from my own answer to a similar question
To get a variable from server to client javascript try templating a json string into the html and loading it from the javascript. EJS handles quote escaping and I think Jade does too. For reference content!= safeString tells Jade to skip escaping, so does content !{safeString}.
- var user={id:1, displayName:'foo'}
#example
meta(data-userJSON=JSON.stringify(user))
script(src="//code.jquery.com/jquery-1.11.3.min.js")
script.
var user = JSON.parse(
$('#example meta').attr('data-userJSON')
)
console.log(user);
span #{user.id}
span #{user.displayName}
Here's how I ended up handling this situation. I simply created a new API endpoint which I can easily hit with an Angular service. Here's the Node setup:
routes.js:
router.get('/currentUser',
apiController.currentUser.index
);
currentUser.js:
var index = function(req, res) {
res.json({user: req.user});
};
module.exports = {
index: index
};
Still seems odd to me to make an API call to get the request parameters, but it works. Feedback appreciated.

AngularJS unwanted Behavior when reloading page

I'm developing an Angular application with the MEAN stack, so suppose you got an express route that make a query to the databse, the results are sent in the response:
app.get('/api', function(req, res){
Todo.find({}, "", function(err,todos){
if (err)
res.send(err);
res.json(todos);
});
});
In the client-side:
Controller :
...
Todo.get().success(function(data){ //i got the service with the $http call
$scope.todos = data;
});
When I go to localhost:8080/#/api, I can see my partial and the data I requested.
The problem that I'm having is that if I omit the hashtag, i don't see the partial, I only see the response data in JSON format.
I also tried to use html5 mode, but if I reload I got the same behavior.
Any ideas on how can I avoid this behavior??
Anything after the # isn't sent to the server. So when you go to localhost:8080/#/api, expressjs just sees a request to / and returns the AngularJS template. AngularJS then routes the browser page using the /#/api, which called the Todo.get() and (I assume) makes a call to localhost:8080/api, returning the data from the DB.
That's why you only get the data when you omit the hash and when you use html5 mode.
I would suggest changing your API call to:
/api/todos - return data from the db
And change your AngularJS route to just use:
/todos - show the partial and data requested

Categories

Resources