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});
});
}
Related
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.
I'm trying to learn the mean stack from the book 'Getting MEAN' which is a little old now, so I'm using more up to date code where applicable. I have just run across an issue that I can't quite solve myself. There is a controller in the book (which uses an older version of angular) written as
var locationListCtrl = function ($scope, loc8rData) {
loc8rData
.success(function (data) {
$scope.data = { locations: data };
})
.error(function (e) {
console.log(e);
});
};
This runs perfectly with the older version of angular, updating it with a more recent version of angular I have the function
let locationListCtrl = ($scope, loc8rData) => {
loc8rData
.then((data) => {
$scope.data = { locations: data };
}, (e) => {
console.log(e);
});
};
This causes an issue with my app and my data is not displaying, and I am getting a [filter:notarray] error, if I remove the filter none of my data is displaying. The part that I am struggling with is that the only thing that has changed is the promise method and the syntax. The data returned by the $http method in loc8rData is the same, assigning it to the scope hasn't changed
$scope.data = { locations: data };
and the browser sees the returned data the same using both methods, which is returned as an array.
So what am I missing, this is driving me mad.
Thanks
The deprecated success() function expects 4 arguments:
data (the body of the response)
status (the status of the response)
headers (the headers of the response)
config (the config object used when sending the request)
The then() function expects a single argument: response. This response object has 4 fields: data, status, headers, config.
So the code should be
locatorData
.then(response => {
$scope.data = { locations: response.data };
}, e => {
console.log(e);
});
Note that I also chose to use locatorData, which is much more readable than loc8rData.
I am trying to test my Ionic app with Jasmine. This is my test suit.
beforeEach(() => {
auth = new Authentication(<any>new HttpMock(), <any>new StorageMock())
user = new MockUser();
header = new Headers({'uid': '1'});
resp = new Response( new ResponseOptions({body: {name: user.name }, headers: header}))
});
it('facebok login ',(done)=>{
spyOn(auth.http,'post').and.returnValue(HttpMock.returnValue(resp));
spyOn(Facebook,'login').and.returnValue(Promise.resolve({authResponse: {accessToken: 1}}))
auth.facebookLogin().then((res)=>{
expect(auth.http.post.calls.argsFor(0)).toEqual([CONFIG.url.facebookUrl,{}])
expect(res.authResponse.accessToken).toEqual(1);
done();
},(err)=>{
done();
});
});
My HttpMock class to mock http calls looks like this.
export class HttpMock {
static returnValue(data){
return Observable.create((observer) => {
observer.next(data);
})
}
}
The relevant part in the service I am testing is,
facebookLogin(): Promise<any>{
let permissions = ["public_profile","email"];
return Facebook.login(permissions)
.then( (response) => {
let token = { access_token: response.authResponse.accessToken };
return this.login( token ,'facebookUrl').toPromise();
}).catch( this.handleError);
login(data , urlKey): Observable<any>{
return this.http.post(CONFIG.url[urlKey], data)
.map( (res: Response) => this.saveUserInfo(res) ).catch( this.handleError)
}
saveUserInfo(res: Response): Response{
let userInfo = this.getUserInfo(res);
this.user = userInfo;
this.storage.set('user', userInfo);
return res;
}
The facebookLogin method goes like this. Access Facebook class login method which returns a promise. With information from the promise, I make http post request and save the returned data and then convert observable to promise with toPromise. In the test I spy on Facebook.login to return a resolving promise and spyOn http.post to return a successful observable. This is working fine in my app.But I am unable to run the test as it give the following error.
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
The code runs fine till the last point in http.post.map but then is not being run in the test. I think the problem is with the toPromise in the service.
Any kind of hep would be appreciated.
From my limited knowledge on Observable , I believe the problem with the approach was due to the fact that toPromise didnt get the value from observer.next(data). I assume subscription is necessary for that. The simple approach with Observable.of worked for me. You can import it from import 'rxjs/add/observable/of'
I have one list which contains list of objects so, now i want to add one more object to the each list in the main list
I am using AngularJS
here is the code which i tried
$scope.mediaList = [];
$scope.getTheProfile = function(data){
for(var i in data)
{
ProfileService.getByHandle(data[i].handle,function(profiledata)
{
$scope.mediaList[i].displayName = profiledata.name.displayName
},
function(data , status){
console.log("In Error");
if(status == '400'){
$scope.errors.push(data["ERROR"])
}
},
function(data , status){
console.log("In forbidden")
})
}
alert($scope.mediaList[0].displayName)
}
so i am trying to add displayName to that list
now the problem is i am not able to get the value in that alert
if that alert is inside ProfileService.getByHandle function then i am getting the value
this is the function getByHandle
this.getByHandle = function(handle, successCB, errorCB, forbiddenCB) {
console.log("In Profile Service for fetching the profile by handle: "+handle);
HttpCommunicationUtil.doGet(apiConstants["profile"]["getByHandle"]+"/"+handle, successCB, errorCB, forbiddenCB);
};
Looking at getByHandle, it seems you are making asynchronous HTTP request using HttpCommunicationUtil.doGet.
What happens is this: for loop will make the HTTP calls and trigger this alert alert($scope.mediaList[0].displayName) without waiting for the response of getByHandle, as it's an asynchronous request.
Therefore, when you try to alert there will be an empty array [] value for $scope.mediaList due to line#1. So $scope.mediaList[0].displayName will produce error saying unable to get displayName of undefined.
You can return promises in ProfileService.getByHandleand when it's resolved use .then to update your variable.
If you can post code for HttpCommunicationUtil.doGet it'll be more useful.
EDIT:
Without HttpCommunicationUtil.doGet, I'll give you an idea of how to do it in a generic way.
Service:
this.getByHandle : function(params) {
return $http.get('/api/endpoint');
}
Controller:
ProfileService.getByHandle(params).then(function(data){
//use data to push response in $scope.mediaList[i]
});
I am trying to use Breeze to get data from a server into an AngularJS app, and although the server is sending the JSON data, the client app is not getting it. The closest I've gotten to identifying the issue using the debugger is to see that the following function getRemoteEntities(), which is part of a Factory, should return a promise but instead returns an empty Object {} when called with a valid entityURL and jsonAdapter:
[...]
var manager = entityManagerFactory.newManager();
[...]
return {
getRemoteEntities: function (entityUrl, jsonAdapter) {
var query = breeze.EntityQuery
.from(entityUrl)
.using(jsonAdapter);
return manager.executeQuery(query)
.then(function (results) {
return results;
})
.catch(function (error) {
return $q.reject(error);
});
}
}
I have checked, and the code does use the Breeze Angular Service as described here. I do not understand what is not working.
EDIT: Removing the .using(jsonAdapter) means that I am able to get and resolve the promise, suggesting that it might be doing something that messes it up. Here is an example (they all follow this pattern):
.value('jsonProfileResultsAdapter', new breeze.JsonResultsAdapter({
name: "xyz", // mild obfuscation
extractResults: function (data) {
var results = data.results;
if (!results) throw new Error("Unable to resolve 'results' property");
return results;
},
visitNode: function (node, parseContext, nodeContext) {
if (node) {
if (node.person && node.assignments) {
return {entityType: "EmployeeModel"}
}
}
}
}))
What is the jsonAdapter doing? That's an unusual feature (not wrong, just unusual). Maybe you're doing something inside it that blows up the promise.
Take it away and see what you get. If you get a promise, even a failed promise, then you're on to something.