AJAX request in React JS js doesn't work - javascript

I'm trying to get info from my database via an AJAX request, but the success event isn't triggered.
The AJAX request is however received by the server, as it trigger the correct console log in the terminal.
I'm building it in Node, using the Express framework.
Here is the code for triggering the AJAX call. The 'componentDidMount triggered' is logged to the console. But then it stops. Neither the console.log in 'success' or 'error' is triggered, even though I know that the server has receenter code hereived an AJAX request.
app.get('/api/:name', function (req,res){
name = req.params.name;
Member.findOne({username: name}, function(err,member){
res.setHeader('Content-Type', 'application/json');
res.write(member.toString());
console.log('member fetched from DB: ', member);
res.end();
});
});
I'm not getting any other errors either, so I have no idea why this isn't working.
Can anybody please help?
UPDATE: Thanks for the help. I'm one step closer now. I did not realise I needed 'res.end' when serving the AJAX request. When I changed this, I've managed to get a response, though it's an error.
Her is the server side code:
app.get('/api/:name', function (req,res){
name = req.params.name;
Member.findOne({username: name}, function(err,member){
res.setHeader('Content-Type', 'application/json');
res.write(member.toString());
console.log('member fetched from DB: ', member);
res.end();
});
});

Tangential to your question, but equally important as figuring out why .success isn't being called: your code is not calling Main's setState in the success handler, because the success function isn't called "in your component" but "by jQuery, somewhere".
If you want to call setState on your component as part of the success handling, either cache the component and then call component functions on that:
var self = this;
$.ajax({
...
success: function() {
self.setState({ ... });
}
...
or use the JavaScript bind function (unrelated to jQuery.bind) to explicitly set the execution context for the success function to be your component:
...
success: function(data) {
console.log('success')
this.setState({data: data});
}.bind(this),
...

My mistake was in the res.write(member.toString()). I had to change it to res.write(JSON.stringify(member)), as the client was asking for a JSON file.

Related

Issuing http get request and accessing the data I'm getting

In my app, I'm issuing get request to retrieve JSON from my server.
$http.get('http://localhost:3000/documents/2.json')
.success(
function(success){
console.log("Success");
})
.error(
function(error){
console.log("error has occurred")
});
Right now, I do successfully get 200 response, but I'm not sure how to access the json file I'm getting from the URL in my web app. I assume there's gotta be something like function(JSONData) but not sure how to implement it in my function above.
I'm issuing this in client side(Written in Angular) and getting the data from the server(written in Rails). My front end (in Angular) is part of Rails app now.
MAJOR EDIT:
This is the version (1.4.9) that the OP is using.
In the AngularJS $http Documentation v1.4.9 you get a sample script of what you are trying to do.
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
inside succes call back write
console.log(success)
so your code must look like this
$http.get('http://localhost:3000/documents/2.json')
.success(
function(success){
console.log("Success");
console.log(success);
})
.error(
function(error){
console.log("error has occurred")
});
parameter(success) in function is data, that you receive from server,
instear of success you can write anything you want .. usually i write data .. so in my case it will be function (data)

jQuery is not calling .done() when the ajax call is successful

We're building a node.js application using Express, but are separating our layers. So the browser is running pure jQuery and javascript, the web server and application server are Node.js and Express. We're using REST APIs between them all.
We're using jQuery 1.10.2
Since the application server cannot be open to the public, the browser must make API calls to the web server, which manages making the call to the application server and returning the results. Here is what that looks like...
// Proxy all other API calls to the backend server
var request = require('request');
app.all('/api/*', function (req, res) {
var targeturl = apihost+req.originalUrl;
console.log("Proxy: "+targeturl);
request({
url: targeturl,
method: req.method,
json: req.body
}, function (error, response, data) {
if(error) {
res.send(error);
res.end();
} else {
console.log("SUCCESS...");
console.log(data);
res.send(data);
res.end();
}
});
});
Our data is a two-level hierarchy of Flows and one or more child Milestones on each Flow. When someone clicks the Save link on our page to save a Flow and its Milestones, the Javascript pulls the Flow data from the page, then makes an AJAX call to save the Flow information first, then waits for the "done()" handler before pulling the Milestone information from the page and making a second AJAX call to save that data. Here is the saveFlow() function executed in the browser...
function saveFlow(organization_id, user_id, flow_id) {
var name = $('#Name').val();
var purpose = $('#Purpose').val();
console.log("Trying to save flow: " + flow_id);
if (name && name.length > 0) {
$.ajax({
url: "/api/flow",
type: 'POST',
datatype: 'json',
data: {
flow_id: flow_id,
name: name,
purpose: purpose,
organization_id: organization_id,
user_id: user_id,
timestamp: (new Date())
}
})
.fail(function (error) {
console.log("Could not save the flow: " + error.message);
})
.done(function (flow) {
console.log("Saving milestones for flow "+flow.id+" ["+flow_id+"]");
saveMilestones(flow.id);
});
} else {
console.log("Refusing to save a flow that has no name");
}
}
The proxy code shows me that this call succeeded...
SUCCESS...
{ success: true,
message: 'Flow Updated!',
id: '56de8e346d229b492a0954f9' }
But the proxy code also demonstrates that the next API call never takes place. Moreover, the log statement in the Done block is never executed, nor are any log statements placed inside the saveMilestones() function.
Clearly, the .done() handler is never being called in this case. I use the done() handler in other parts of my code and it works. I've compared the code but don't see any differences. The proxy code we're using is driving every other API call made from our pages successfully, so I don't think that it's failing to return the success status.
I've done a lot of searching on this site and tried every suggestion I could find - adding a explicit "json" datatype parameter, switching from ":success" to ".done()" - but nothing has worked yet. I even tried switching from done() to always() - a bad idea but I wanted to see if it would get called...and it wasn't called.
It's also worth noting that the .fail() handler is also not being executed.
Is it possible that the JSON block we're sending back to indicate success is somehow failing to make jQuery realize that we were successful? Or is it possible that the AJAX call is crashing when it tries to process the successful return? If so, how do I catch that to prove it and fix it?
Hope someone can help.

Backbone Response on Sync

First of all my knowledge of Backbone is very limited, and currently, I'm trying to add an implementation into some code I didn't create.
My problem is as follows:
I have a collection which is being rendered on click of a button. Now, we are setting some permissions on the website, so that sometimes the response I will get is a 401.
I'm currently able to get the response, the problem is that I don't know how to attach it to the sync event so that if I get a 401 when I call the API, it shouldn't render anything.
I would think looking at the code would help clarify my problem:
this.addressBook = new (Backbone.Collection.extend({
url: url,
model: Backbone.Model.extend({
idAttribute: 'ID'
}),
parse: function(data) {
return data;
}
}))();
this.addressBook.on('sync', this.renderAddresses, this);
this.addressBook.fetch();
So I found a few ways to get the status code from fetch, but in this particular case, I need to get the status code before the sync event calls this.renderAddress, and given the status of the response, go ahead and render my view or simply display a message stating that access is denied.
Sorry if I'm not clear enough.
Thanks in advance.
Here is the salient part of the backbone documentation:
Whenever a model or collection begins a sync with the server, a "request" event is emitted. If the request completes successfully you'll get a "sync" event, and an "error" event if not.
This means that the sync event shouldn't fire if you get a 401, rather the error event should be triggered.
You can test this in your code by listening to all the different events (all available parameters included):
this.listenTo(yourCollection, 'request', function(collection, resp, options) {
console.log('Request: ', resp);
});
this.listenTo(yourCollection, 'error', function(collection, resp, options) {
console.log('Error: ', resp);
});
this.listenTo(yourCollection, 'sync', function(collection, resp, options) {
console.log('Sync: ', resp);
});
So you should be able to just listen to the error event to display your custom error message:
this.listenTo(yourCollection, 'error', function(collection, resp) {
if (resp.status === 401) {
console.warn('401: Unauthorized');
} else {
// do something else
}
});
First of all, you will need to define some callback options for you addressBook fetch. For what you are trying to accomplish, you need to provide the error callback.
this.addressBook.fetch({
error: function(xhr) {
if(xhr.status == 401) { // Put logic you want in the case of 401 here...
}
});
Disclaimer: I have not tested this code, as I do not have a convenient way I can think of to reproduce this problem.
I believe it works because Backbone passes a jQuery xhr Object to its error callback. http://backbonejs.org/#Model-fetch

Backbone Create

For some reason this.collection.create() is returning an error, but interestingly, the error message seems like the model I just added to my collection.
this.collection.create({
name: $('#big-input').val(),
firstRemark: $('#small-input').val(),
postedBy: window.user.displayName,
twitterHandle: window.user.twittername,
pictureUrl: window.user.profilePic
},{wait: true,
success: function(response){
console.log("success");
console.log(response)
},
error:function(err){
console.log(err)
}
});
this is what I get after console.log(err):
exports.newPost = function(req, res){
console.log("GOT NEW TWEET REQUEST");
var newPost = new Post(req.body)
newPost.dateCreated = new Date();
newPost.save();
res.send(200);
};
Thanks to answers below I was able to print my 'real' error. As seen below xhr.responseText is 'OK' and 'status' is 200. Why is this response triggering a success but an error?
I also have a parse method in my collection
parse: function(response){
this.page = response.page;
this.perPage = response.perPage;
this.total = response.total;
this.noofpages =response.noofpages;
return response.posts;
},
This is expected. Have a look at the Model.Save documentation, which says the error callback will be called with (model, xhr, options) as it's parameters.
If you want the actual contents of the response you can get it from the second parameters responseText property: xhr.responseText. There's more details on jqXHR elements in the jquery documentation: http://api.jquery.com/jQuery.ajax/#jqXHR
The parameters of your success callback are also not quite right - it takes (model, response, options)
EDIT:
Not entirely sure if it's the cause of your problems, but your server should be returning a 200 status code and the models JSON on success. Have a look at the Backbone.Sync documentation.
From looking at the code this does look important when passing wait: true as an option, as the attributes set are extended with the returned attributes from the server. Have a look at the options.success function used by backbone here to see what I mean. It certainly looks like something might go wrong if you return "OK" from the server, though I'm not sure if it'd be exactly the problem you're experiencing.
EDIT2: Slight correction to what I wrote above: The return value gets passed through Model.parse. Since you've defined a custom parse function, the server should return something that is going to work with it, rather than just plain JSON for the model.
The error function will receive 3 arguments as defined in the wrapError function in backbone.js
model.trigger('error', model, resp, options);
Therefore what your output is, is correct. You will want to add a variable to your error function to capture the response (2nd argument) and log that instead to help you debug.

node.js missing post data in async request

I'm making a simple form in Node.js. Everything else seems to be working correctly, but the function that is supposed to receive post request data is never getting called. Here's the relevant code snippet:
if (request.method == 'POST') {
var body = '';
console.log(request.body);
request.on('data', function (chunk) {
console.log("got the post request data"); //nothing logged to console
body += chunk;
});
request.on('end', onRequestEnd(body, response));
}
The function onRequestEnd does get called, but later my code breaks when there's nothing but an empty string in the parameter body. Is the keyword 'data' correct?
The code was modified from an answer here: How do you extract POST data in Node.js?. I'll post more if needed.
After lots of frustration I solved the problem myself!
I changed the line:
request.on('end', onRequestEnd(body, response));
to:
request.on('end', function() {
onRequestEnd(body, response);
});
It had something to do with callbacks. I'm not exactly sure why this works and the other one doesn't though. This is how I feel: http://www.masti-xpress.com/images/Story-of-Every-Programmer.jpg
I'll share how I solved the problem with this.
I had another view of it however and I'll share that as well.
What I wanted was to have something like this in my "view".
app('/urlToView', function(req, response){
request.on('end', function() {
var post = **request.data;** //sanitize data
resolver.renderTemplateOr404('start.html', post, request, response);
});
}
The request.data is the important thing to notice here.
However I haven't really solved how to "not" have the request.on('end'...) in my view yet.
A reason as to why the console.log() would be how you handle the callback from the function that you do all this work in.
I hijack the request before it lands in my view when I start the server
self.preProcess(self, request, response);
and
preProcess: function onRequest(app, request, response){
processor.preRequest(request);
}
and lastly int the preRequest() function I do
if (request.method === 'POST') {
var postdata = "";
request.on('data', function(postdataChunk){
postdata += postdataChunk;
});
request.on('end', function(){
_transformRequest(request, _transformPostdata(postdata)); //this is to set the data on the request
});
}
and adding a console.log(postdataChunk); here isn't a problem since all of the callbacks are properly handled.
Also, this might be very stupid of me to ask but are you aware of that console.log(); doesnt output to browser but to the terminal window?
This might not be an exact answer for you but I hope this helps a bit.

Categories

Resources