ReactJS actions not loading data through ajax call - reactjs

I have a requirement wherein I need to load the data through an ajax call to server and then pass on the data to reducer to render my page through props.
But I see the data in the ajax call is being shown as undefined.
function getInitData(url) {
axios({url: url, timeout: 20000, method: 'get', responseType: 'json'})
.then(function(response) {
console.log(response.data.results)//--DATA DISPLAYED
return response.data.results
})
.catch(function(response) {
console.error(response.data);
})
}
let formActions = {
loadInitJSONSchema: function(formSchema) {
let dataLoaded = getInitData('/startInterview')
console.log(dataLoaded);//--DATA DISPLAYED as UNDEFINED
return {type: 'LOAD_INIT_JSON_SCHEMA', formSchema: dataLoaded}
}
}
I dont know why my data displayed as undefined in my actual method may be it is because of the asynchrnous call?? If so how do I load my data in actions??
Please find the complete code at the URL

It's promises all the way down.
A jQuery example: jQuery('body') does not return the body element. It returns a jQuery collection. jQuery('body').css('background', 'red'); also returns a jQuery collection. It's collections all the way down.
axios.get().then(function(response) { return response; }) does not return response. It returns a promise.
First, change this, to return the promise:
function getInitData(url) {
return axios...
Then change your function:
loadInitJSONSchema: function(formSchema) {
return getInitData('/startInterview').then(function(data) {
return {type: 'LOAD_INIT_JSON_SCHEMA', formSchema: data}
})
Then anyone who uses loadInitJSONSchema gets the promise and gets the value in a .then().
loadInitJSONSchema(schema).then(function(result) { ... do something with result })
It's promises all the way down.
This flow is asynchronous. With var something = axios.get().then(function(response) { return response; }) the code is evaluated in place and the program keeps going. The .then() callback happens at a later time, long after the current function has finished executing.

Related

Cannot get Promise values Return from api from openWeather

I have a few problem while integrating api from OpenWeather.
I can successfully log the response data value from the api. But when i call from another component with .then(), throw me the error.
The following is my api.js call with axios
function getFiveDayForcast(cityName) {
axios.get(`http://api.openweathermap.org/data/2.5/forecast/daily?q=${cityName}&type=accurate&APPID=${apiKey}&cnt=5`)
.then(function(response){
// console.log("response" , response.data);
return response.data;
})}
module.exports= {getFiveDayForecast:getFiveDayForecast}
This is when i call back from my Component
componentDidMount(){
let city = queryString.parse(this.props.location.search).city;
this.makeRequest(city);
}
makeRequest =(city) => {
//set loading false
this.setState(()=> ({loading:false}));
api.getFiveDayForecast(city).then((response) => {
console.log(response)
})
}
And it throw
TypeError: Cannot read property 'then' of undefined
Would be nice if someone can explain in details about it. I am also reading documentation as well. Thanks in advance.
Posting my answer here so more people can see.
Referring to Returning an Axios Promise from function
The complaint is that a function needs to return something in order for the then chain to know what to do. The function preceding the then chain is not returning anything, so the function inside then then chain doesn't know what to do.
Axios takes care of this for the get action, but you aren't directly chaining the get method to then. Instead, you are chaining a method you created, getFiveDayForcast.
You should change getFiveDayForcast(cityName) (btw 'Forecast' is the right spelling) to
function getFiveDayForcast(cityName) {
const request = axios.get(`http://api.openweathermap.org/data/2.5/forecast/daily?q=${cityName}&type=accurate&APPID=${apiKey}&cnt=5`)
.then(function(response){
// console.log("response" , response.data);
return response.data;
})
return request;
}
You need to return the Promise from your Function getFiveDayForcast.
function getFiveDayForcast(cityName) {
return axios.get(`http://api.openweathermap.org/data/2.5/forecast/daily?q=${cityName}&type=accurate&APPID=${apiKey}&cnt=5`)
.then(function(response){
// console.log("response" , response.data);
return response.data;
})
}

ReactJS & Flux get data from promise

I am trying to get data from server with service function that I found in a template reactjs project. I do recieve a perfectly fine anwser from the server, I can see the arrays are ok while still in the service, but not when handed over to the component that called for it in the first place. At the component I get a promise object, which has the values (I have seen them in console) but I can't access them. What am I missing?
My component has following function:
calculate(dict) {
var results = Service.calc(dict)
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
});
this.setState({results:results._handler});
}
When I printed the results in to console I saw the Promise object, inside _handler.handler was a value array with my values but I couldn't use them. The error appeared when accessing the results._handler.handler: undefined.
The called service looks like this:
class Service {
calc(dict) {
return this.handleCalculate(when(request({
url: UserConstants.URL,
method: 'POST',
type: 'json',
data: dict
})));
}
handleCalculate(calcPromise) {
return calcPromise.then(
function(data) {
console.log(data); //Success
return data;
}
)
}
Meanwhile I use ajax call directly in the component instead of the service. But I understand that is bad practice, how can I get this right?
Hi basically you put setState in the wrong place. (It sets state right away without waiting for result getting resolved). It should look like this
calculate(dict) {
var results = Service.calc(dict)
.then(results => {
this.setState({results: results});
})
.catch((err) => {
var errResp = JSON.parse(err.response);
console.log(errResp);
this.setState({responseErrors: errResp});
});
}

Angular JS 1.X Access Resolved Promise Objects values

I have read a lot of posts on promises,resolving promises, and accessing the data however I cannot seem to. Following some posts on Stack Overflow has just caused errors, so I am not sure what exactly I am doing wrong.
I have a function like so:
function getJsonl() {
var deferred = $q.defer();
$http({
url: 'urlNotShownForSecurity',
dataType:"json",
method: 'GET',
data:{"requestId":"123"},
headers:{"Content-Type":"application/json","requestId":"123"},
}).success(function(data) {
deferred.resolve(data);
console.log(data)
}).error(function(error,status,headers,config) {
deferred.reject(error);
});
return Promise.resolve(deferred.promise);
}
Here I return a json promise that has been resolved resulting in a json object I believe.
Printing to console I get the following:
Inside data is the information I need, it looks like this:
data:Array[8]
0:Object
description:"My description paragraph"
I have tried things with the returned object in my controller like:
vm.result = data.data[0].description;
vm.result = data[0].description
I have tried many different approaches in the view as well to access but I get 2 blank li tags and that is it.
I would like to be able to access the data so I populate a table. So if I can use it with ng repeat that would be great, as well as being able to access without because some data is used in more than just the table.
Update
#DanKing, following your implementation I get the following output in console:
Now I am back with a promise object.
It looks to me as though you're fundamentally misunderstanding the nature of promises.
$http() is an asynchronous function - that means it doesn't complete straight away, which is why it returns a promise.
It looks to me as though you're trying to call $http() and then get the result back and return it from your getJson1() method, before $http() has finished executing.
You can't do that. Your getJson1() method should just return the promise, so your calling method can chain onto it - like this:
getJson1().then(function(data) {
// do some other stuff with the data
});
The whole point of promise chains is that they don't execute straightaway - instead you provide callback functions that will be executed at some indeterminate point in the future, when the previous operation completes.
Your getJson1() function just needs to do this:
return $http({
url: 'urlNotShownForSecurity',
dataType:"json",
method: 'GET',
data:{"requestId":"123"},
headers:{"Content-Type":"application/json","requestId":"123"},
});
getJsonl().then(function(data){
console.log(data);
},function(err){
console.log(err);
})
should work. Where is your $http request and where is your call to getJsonl() will also make a difference. So choose that carefully when implementation. If you are using this in a service then you will have to return the function result say
this.somefunction = function (){
return getJonl();
}
and in your controller inject the service and do the following
service.somefunction().then(function(data){
console.log(data);
},function(err){
console.log(err);
})
Ok, rewrote the answer as a complete component to show the moving parts.
$http returns a promise so your original getJsonl call can be simplified. Using your original $http parameters this should dump your API response to the screen if you use the <json-thing> tag:
angular.module('yourModuleName')
.component('jsonThing', {
template: '<pre>{{$ctrl.thing|json}}</pre>',
controller: function ($http) {
var $ctrl = this;
getJsonl()
.then(function (response) {
console.log(response); // we have the $http result here
$ctrl.thing = response.data; // allow the template access
}, function (error) {
console.log(error); // api call failed
});
// call backend server and return a promise of incoming data
function getJsonl() {
return $http({
url: 'urlNotShownForSecurity',
dataType: 'json',
method: 'GET',
data: { requestId: '123'},
headers: { 'Content-Type': 'application/json', requestId: '123'}
});
}
}
});

catch errors/read status code from rest call - angular

How do you catch errors/read http status code when making a rest call in one of these formats, both work to return a successful response, just no idea how to grab the info i need. I can get the object with values returned as I need, I just cant get the http status code.
methods provided by #Claies in a response to this question (Get data from $resource response in angular factory)
$scope.makeRestCall= function () {
$scope.member = Item.makeRestCallWithHeaders('123456789', '789456123')
.query().$promise.then(function(response){
});
};
$scope.makeRestCall= function () {
$scope.member = Item.makeRestCallWithHeaders('123456789', '789456123')
.query({}, function() {
})
};
I have tried to use the first method here and grab something from the function(response) such as response.status, but it returns undefined.
For reference, using this factory:
.factory("Item", function($resource) {
var endpoint = "http://some valid url";
function makeRestCallWithHeaders(id1, id2) {
return $resource(endpoint, null, {
query: {
method: 'GET',
headers: {
'id1': id1,
'id2': id2
}
}
})
}
var item = {
makeRestCallWithHeaders: makeRestCallWithHeaders
}
return item ;
})
Item returns something like this:
{firstName:Joe, lastName:smith}
I am really just trying to figure out how I can access the status code returned by the REST call. Absolute end goal is to read any error response and return error to UI written in angular as well. If there is a way to just read this in the UI, that could work too.
To read the error status you need to pass in the errorCallback to the $promise:
$scope.makeRestCall= function () {
$scope.member = Item.makeRestCallWithHeaders('123456789', '789456123')
.query().$promise.then(
function(response){
//this is the successCallback
//response.status & response.statusText do not exist here by default
//because you don't really need them - the call succeeded
//see rest of answer below if you really need to do this
// but be sure you really do...
},
function(repsonse) {
//this is the errorCallback
//response.status === code
//response.statusText === status text!
//so to get the status code you could do this:
var statusCode = response.status;
}
);
};
You shouldn't need the status in the successCallback, because it is a success and you know the success code implicitly.
Therefore the status is not available in the successCallback by default.
If, for some reason, you do need the status in your successCallback, you could write an interceptor to put this information somewhere, but be aware that the angular framework deals with the data differently in different success scenarios so you will need to write code for different cases.

How to call Success or Error on binded methods (Controllers, Factorys)

I am trying to figure out how handle success and error on binded methods that return an http response.
I am trying to bind a factory method to a controller, so I am able to call it from the view. This method will try to add an item to the shopping cart via an http request. If it fails the method that is being called will return false, however if it succeeds it will return the http response.
I want to be able to somehow add success or error callbacks to the binded method. Is this possible?
Car controller
// Controller to display cars page
app.controller('carsController', function($scope, $rootScope, inventoryFactory) {
// Function that will fetch JSON and save all necessary data for us to use
function init() {
// Bind these method calls to our cart factory
// Allow method to be called from the view
$scope.addToCart = userFactory.addToCart;
// Get list of items in car category
inventoryFactory.getItems('cars').success( function(data) {
$scope.items = data;
});
}
init();
});
userFactory
// Add item of given ID to shopping cart
factory.addToCart = function(itemID) {
// Validate our user / token
data = factory.getUserToken();
if (data === false) {
return false;
}
req = {
method: 'PUT',
url: 'routes.php/api/shoppingcart/' + itemID,
headers: {
'X-Api-Token': data.apiToken,
'UserID': data.userID
}
};
return $http(req);
};
What you are doing will work, but I would recommend a few changes.
First, direct binding may cause problems. If your factory method at any point needs to call this, it will lose it, since this becomes the $scope rather than the returned object from the factory.
$scope.addToCart = userFactory.addToCart; // addToCart will have "this" be of $scope
Whereas you can keep it either by proxying or by wrapping:
$scope.addToCart = function(id) {
return userFactory.addToCart(id);
};
guarantees that addToCart inside the factory has the correct context for this.
Second, while you can do what you want, if you are returning a promise (as $http() does), then sometimes returning false and sometimes returning a promise can lead to messy code and difficulty testing. You may be better off always returning a promise and rejecting it as necessary:
var defer, ret;
data = factory.getUserToken();
if (data === false) {
defer = $q.defer();
defer.reject();
ret = defer.promise;
} else {
req = {
method: 'PUT',
url: 'routes.php/api/shoppingcart/' + itemID,
headers: {
'X-Api-Token': data.apiToken,
'UserID': data.userID
}
};
ret = $http(req);
}
return ret;
This way you will always have a promise, and can always do
addToCart(25).then(function(){/* success */),function(){/* failure */});
If you need to do error handling, you might want to handle it inside your controller. So if your template is:
<button ng-click="addToCart(item.id)">Click me!</button>
Then your controller addToClick might be:
$scope.addToCart = function(id) {
userFactory.addToCart(id).then(function(results){
// indicate success on the screen by changing some scope var, e.g.
$scope.message = "Successfully added to cart";
},function(err){
// indicate error on the screen by changing some scope var, e.g.
$scope.message = "Problem adding to cart: "+err;
});
};

Resources