FYI: There is main question on the bottom if you ever feel like my post is too long ;)
Im trying to build my first angularjs app and now Im stuck with collecting data via ajax from nodejs (express) server.
In front-end Im loading templates with angularjs routers and ng-view. In every route i have template and specific controller (this should be pretty basic thing right?).
OK here comes the wall... I was thinking to put $http.get() to load right stuff for the template from the nodejs server in the controller. With GET I could send variables like this.
$http.get('http://.../API', { params: { twitterData : true, needed : "data2" } } )
.success( function(result) {
// pass result to template.
});
And then on the server side get params like this.
router.get('/', function(req, res) {
this.params = req.query;
// here run every function and collect it to one object
// then return it for front-end ajax call.
res.send(JSON.stringify(collectedDataObj));
}
collectedDataObj could look something like this:
{ twitterData :
{ thisIs:twitterObject },
blog : {title: "...", content: "..." }
}
Collecting data would be by nested callbacks like introduced here http://book.mixu.net/node/ch7.html
So is this "collecting all data in back-end" best way to get data or should I send many ajax calls to collect data for one angular view?
Meaning one $http.get() for getting titter object and one for blog content etc.
And of course if you know some pass me links for good tutos/examples.
IMO, whenever possible it's best to get everything you can in one request. Trips back and forth to the server get pretty expensive.
Related
I'm building a web app that is going to use an API to display cards when you hover over card text on the app.
I'm using unirest to make the call to the API on my node express server as follows -
unirest.get("https://omgvamp-hearthstone-v1.p.mashape.com/cards")
.header("X-Mashape-Key", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
.end(function (result) {
console.log(result.status, result.headers, result.body);
});
The data returns correctly and is displayed in my git bash console as JSON.
How do I use the Angular $get service to make a call against what node has just pulled? I guess my question is , where is this data pulled to once node gets a handle on it?
From what I understand, I would parse this information, but do I have to send this data to use it in my Angular.js file?
I hope I wrote enough information for an answer.
Thank you
If you want to pass the data to your UI, you need to make it accessible through an endpoint, so you could do something like this in your server (I'm using express for simplicity):
app.get('/my-data-endpoint', (req, res) => {
unirest.get("https://omgvamp-hearthstone-v1.p.mashape.com/cards")
.header("X-Mashape-Key", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
.end((result) => {
console.log(result.status, result.headers, result.body);
res.send(result);
});
});
and in your angular controller you can do:
$http.get('/my-data-endpoint')
.then((response) => {
console.log(response);
});
just remember to inject the $http dependency in your controller and you should be able to see the response.
I know how to send an http request to a server using angular js. With the promise returned, I know how to listen for a response and manipulate the ui thereafter. But this approach cannot be used for what I have in mind.
However, what I cannot figure out, is how to send a request to a website.
I have a server localhost:800/receiveData which receives a POST request and then manipulate the UI and DoM on the angularjs site
app.get('/', function(req,res){
res.sendFile(__dirname+'/index.html')
})
app.post('/receiveData', function(req,res){
var data = req.body.data
// assume data is a boolean
if(data){
//show a view in index.html using angular js or anything else
}else {
//show a different view in index.html
}
});
Any help will be greatly appreciated. I have a need for angular js. Having a SPA is imperative. I am completely open to adding additional stacks if neccessary.
EDIT:
As pointed out by MarcoS, manipulation of dom should ideally not happen from the server side. I am combining IPFS with node js and angular js to develop a single page application. The swarm of nodes set up using IPFS has an open line of communication with my server (by design). Based on packets of data sent via the comm line to my server, I need to convey messages to the user via the index.html.
I think your approach is wrong: on server-side, you should NOT manipulate the UI and DOM...
You should just do server activity (update a database, send an email, ..., return a static page).
Then you can output a result (JSON/XML/... format) for your client-side calling script to read.
Following OP edit, what I do understand is he wants server push to the client.
To get serve side pushes, you should poll on the client.
In a controller:
function getServerState(changeState) {
return $http.get("/receiveData").then(function(res) {
changeState(res.data); // notify the watcher
}).catch(function(e) {
/* handle errors here */
}).then(function() {
return getServerState(changeState); // poll again when done call
});
}
Consuming it this way:
getServerState(function(status) {
$scope.foo = status; // changes to `foo` $scope variable will reflect instantly on the client
});
And, server side:
app.post('/receiveData', function(req, res) {
var data = req.body.data; // assume data is a boolean
res.end(JSON.stringify(data);
});
Coming from a .net world where synchronicity is a given I can query my data from a back end source such as a database, lucene, or even another API, I'm having a trouble finding a good sample of this for node.js where async is the norm.
The issue I'm having is that a client is making an API call to my hapi server, and from there I need to take in the parameters and form an Elasticsearch query to call, using the request library, and then wait for the instance to return before populating my view and sending it back to the client, problem being is that the request library uses a callback once the data is returned, and the empty view has long been returned to the client by then.
Attempting to place the return within the call back doesn't work since the EOF for the javascript was already hit and null returned in it's place, what is the best way to retrieve data within a service call?
EX:
var request = require('request');
var options = {
url: 'localhost:9200',
path: {params},
body: {
{params}
}
}
request.get(options, function(error, response){
// do data manipulation and set view data
}
// generate the view and return the view to be sent back to client
Wrap request call in your hapi handler by nesting callbacks so that the async tasks execute in the correct logic order. Pseudo hapi handler code is as following
function (request, reply) {
Elasticsearch.query((err, results) => {
if (err) {
return reply('Error occurred getting info from Elasticsearch')
}
//data is available for view
});
}
As I said earlier in your last question, use hapi's pre handlers to help you do async tasks before replying to your client. See docs here for more info. Also use wreck instead of request it is more robust and simpler to use
I am trying to determine if i can call res.send(data) and then res.render('reports') simultaneously.
To explain further in detail, when i route to '/reports', first on my server side i making a REST call to an API which returns back json data. Now i want this json data to be accessed on the client, for which i am making an ajax call from my javascript. Hence the use of res.send(), but i also want to render the page in this call
So it looks like the following on my server side code
router.get('/reports', function(req,res){
//Making the REST Call to get the json data
//then
res.send(json);
res.render('reports');
});
Every time i hit the '/reports' on the browser, I see the json value instead of the page being rendered and my console throws an Error: Can't set headers after they are sent.
You could use content negotiation for that, where your AJAX request sets the Accept header to tell your Express server to return JSON instead of HTML:
router.get('/reports', function(req,res) {
...
if (req.accepts('json')) {
return res.send(theData);
} else {
return res.render('reports', ...);
};
});
Alternatively, you can check if the request was made with an AJAX call using req.xhr (although that's not 100% failsafe).
No you can't do both, but you could render the page and send the data at the same time:
res.render('reports',{data:json});
and then access those data in the newly rendered page.
alternatively you could send a flag when making the call , and then decide whether you want to render or send based on this flag.
Ideally, it needs to be 2 separate route, one spitting json and other rendering a view. Else, you could pass a url param, depending on which you return json or render a view.
router.get('/reports/json', function(req,res){
var data = JSON_OBJECT;
res.send(data);
});
router.get('/reports', function(req,res){
var data = JSON_OBJECT;
res.render('path-to-view-file', data);
});
No, you can't. You can only have a single response to a given request. The browser is either expecting an HTML document or it is expecting JSON, it doesn't make sense to give it both at once.
render just renders a view and then calls send.
You could write your view to output an HTML document with a <script> element containing your JSON in the form of a JavaScript literal.
My app is Backbone.js for client-side, Express.js for back-end.
I have problems with syncing with all parts of my API, using the backbone model and collection(they use urlRoot: "/users").
I'm allowed to use only GET or POST, no PUT or DELETE.
*I'm not allowed to use more models*
Not allowed to use jQuery ajax
My API
add new user:
I need to make a POST to /users with JSON of new data. So I did it just fine with - this.model.save({new data...})
list all users:
My API for that, responses to GET /users, with the right handler - so, this.collection.fetch() - works fine.
Log-In:
My API accepts POST to /users/login for that. How can I add a function "logIn" to my model, that will use custom sync/pass options.url to sync - or any other way - that will POST to /users/login ?
Log-Out:
API accepts POST to /users/logout - how to send this request using my backbone model ?
User By ID:
Same question here for GET /users/:id
Update user:
POST /users/:id - same question again.
--- So actually, the question in short is ---
What is the best way (or the most "right"), to implement methods of a backbone model, that are similar to "model.save()" - but just POST/GET to a bit different path then urlRoot ?
You probably have a couple options here. One would be structuring your models in a way that supports the urls you want. For instance, have a User model and a Session model that deal with updating the user and managing the logged in state separately.
The other thing you should probably do is to use the url method in your models.
Something like this in your User model. (Note: using urlRoot instead of url here is identical, but this is the correct approach for anything more complicated that is needed in the url)
url : function() {
var base = "/users/";
if(this.isNew()) {
return base;
} else {
return base + this.get("id");
}
}
You could extend this same concept to work in your Session model for handling logout vs login based on if the Session is new or not.
Update:
If you must use the same model, the best thing would be to totally bypass the Backbone.sync method and write a custom AJAX call with success/error handlers that know how to clean things up.
login : function() {
$.post("/users/login", {success: function (response) {
// Update user as needed
}, error: function (xhr, response) {
// Handle errors
}
}
}