Promise does not return the right object - javascript

I have a problem with the following chain of promises:
Parse.Cloud.run('cloudlogin', {
fb_accessToken: $localStorage.accessTokenFacebook
, facebookID: FACEBOOKID
}, {
success: function (userdata) {
alert(JSON.stringify(userdata))
$localStorage.username = userdata.username;
$localStorage.password = userdata.password;
$localStorage.fb_access_token = userdata.fb_accessToken;
var bool = userdata.isnewuser
alert('bool' + bool)
return bool
}
, error: function (error) {
alert(error)
$state.go("login")
.then(function () {
$ionicLoading.hide()
})
}
})
.then(function (isnewuser) {
$localStorage.organizerAccess = true;
alert('fbdata' + JSON.stringify(isnewuser))
})
I would like to make the first promise to return the boolean 'isnewuser' to the second promise but instead the whole 'userdata' object is returned. Any idea?

success is a callback function its return value won't pass to the next then. if you want to pass the bool value to next one need to rewrite code like below.
Parse.Cloud.run('cloudlogin', {
fb_accessToken: $localStorage.accessTokenFacebook
, facebookID: FACEBOOKID
}, {
error: function (error) {
alert(error)
$state.go("login")
.then(function () {
$ionicLoading.hide()
})
}
}).then(function (userdata) {
alert(JSON.stringify(userdata))
$localStorage.username = userdata.username;
$localStorage.password = userdata.password;
$localStorage.fb_access_token = userdata.fb_accessToken;
var bool = userdata.isnewuser
alert('bool' + bool)
return bool
})
.then(function (isnewuser) {
$localStorage.organizerAccess = true;
alert('fbdata' + JSON.stringify(isnewuser))
})

as the documentation says - then(successCallback, [errorCallback], [notifyCallback]) – regardless of when the promise was or will be resolved or rejected, then calls one of the success or error callbacks asynchronously as soon as the result is available. The callbacks are called with a single argument: the result or rejection reason. Additionally, the notify callback may be called zero or more times to provide a progress indication, before the promise is resolved or rejected.
so, instead of taking the returned value then takes the object returned which caused the success: function (userdata) which is userdata

login: function () {
var deferred = $q.defer();
Parse.Cloud.run('cloudlogin', {
fb_accessToken: $localStorage.accessTokenFacebook,
facebookID: FACEBOOKID
}).error(function (error) {
alert(error)
$state.go("login")
.then(function () {
$ionicLoading.hide()
})
})
.then(function (userdata) {
alert(JSON.stringify(userdata))
$localStorage.username = userdata.username;
$localStorage.password = userdata.password;
$localStorage.fb_access_token = userdata.fb_accessToken;
deferred.resolve(userdata.isnewuser);
});
return deferred.promise;
}
write this function in service class and call it from controller

Related

Figuring the complexity of Promise.all

I have been struggling for quite some time to get this multiple async nodejs request apis to work but unfortunately i am not able to get them work.
Index.js Code:
service.get(
"/restraunts",
versionRoutes({
"1.0.0": getRestrauntsList
})
);
function getRestrauntsList(req, res, next) {
console.log("Started getRestrauntsList");
file1
.appEnvironment(req, res, next)
.then(function(result) {
return file2.getRestrauntsList(req, res, next);
})
.then(function(result) {
res.status(200).send(result);
return;
})
.catch(function(errorResult) {
res.status(500).send(errorResult);
return;
});
}
File2.js
module.exports = {
getRestrauntsList: function(req, res, next) {
console.log("getRestrauntsList started..");
var cities = [1, 2, 3, 4, 5];
let restrauntsList = [];
let urlArray = [];
var restrauntsListPromise = cities.map(function(id) {
return new Promise(function(resolve, reject) {
var options = {
method: "GET",
url: "someurl/" + id + "/restaurants",
headers: {
"AUTH-TOKEN": "TOKEN"
}
};
request(options, function(error, response, body) {
if (error) {
if ("message" in error) {
errorMsg = error.message;
var result = {
status: "error",
message: errorMsg
};
} else {
var result = {
status: "error",
message: "Resource Timeout."
};
}
reject(result);
return promise;
}
console.log(
"Response: " + JSON.stringify(response)
);
if (response.statusCode === 200 || response.statusCode === 201) {
body = JSON.parse(body);
if (body.success) {
let result = {
status: "success",
data: body.result
};
resolve(result);
} else {
let result = {
status: "error",
message: body.error
};
reject(result);
}
} else {
let result = {
status: "error",
message: body.error
};
reject(result);
}
});
});
});
console.log('restrauntsListPromise:' + JSON.stringify(restrauntsListPromise));
Promise.all(restrauntsListPromise).then(function(result) {
var content = result.map(function(restraunts) {
return restrauntsList.push(restraunts.body);
});
// res.send(content);
resolve({
restrauntsList: restrauntsList
});
return promise;
});
},
};
Ideally i expect to get the response of all the apis in the
restrauntsListPromise
and then using Promise.all i should iterate all the promises and formulate my required object.
The response of my code however is
restrauntsListPromise:[{},{},{},{},{}]
and then
Response: {"statusCode":200,"body":"{\"success\":true,\"res
Response: {"statusCode":200,"body":"{\"success\":true,\"res
Response: {"statusCode":200,"body":"{\"success\":true,\"res
Response: {"statusCode":200,"body":"{\"success\":true,\"res
Response: {"statusCode":200,"body":"{\"success\":true,\"res
Ideally what should happen is i should be able to pass the combined result of all the five apis calls as a single object back to the calling promise here
.then(function(result) {
res.status(200).send(result);
return;
})
The problem being the method getRestrauntsList finishes execution and then after some time, i get the responses of the apis.
The problem being the method getRestrauntsList finishes execution and then after some time, i get the responses of the apis.
This is because you're not returning a promise from the getRestrauntsList().
There are few items that needs to addressed to make it work
1. Remove the unused variables
return promise; // both inside promise.all[] and request()
There is no declared variable named promise. So, you can remove it.
2. Accessing .body instead of .data
You're resolving as resolve({status: "success", data: body.result}); But When you are iterating, you are accessing using .body instead of .data. You need to be using .data. Also, you can eliminate restrauntsList array since you're using a .map()
3. Calling resolve() to return values.
You can't use resolve() to return value within Promise.all[] since you didn't create a promise using new Promise((resolve, reject) => { ... });. By default, a return within a promise will be a promise. so, a simple return will suffice. But if you want to be explicit, you can also return using Promise.resolve()
Making those changes,
return Promise.all(restrauntsListPromise).then(function (result) {
return {
restrauntsList: result.map(function (restraunts) {
return restraunts.data;
})
};
//or using Promise.resolve();
// return Promise.resolve({
// restrauntsList: result.map(function (restraunts) {
// return restraunts.data;
// })
// });
});
You are looking for
return Promise.all(restrauntsListPromise).then(function(result) { /*
^^^^^^ */
var contents = result.map(function(restaurants) {
return restaurants.body;
// ^^^^^^^^^^^^^^^^^^^^^^^^
});
return {restaurantsList: contents};
// ^^^^^^
});
You need to return the promise chain from the getRestrauntsList method, you should return the value from the map callback instead of using push on an array, and you will need to return from the then callback - there is no resolve function as you're not inside a new Promise constructor that you only need for callback APIs.

Returning a value in function export using promises when second function is complete

I'm trying to return a value after a promise runs a function once all promises are completed like the code below.
var promises = [];
var userInfo = null;
export function userRunner(userData) {
userData.forEach(function (obj) {
let x = fetch(apiURL1)
.then(function (data) {
return data.json()
})
promises.push(x);
let y = fetch(apiURL2)
.then(function (data) {
return data.json()
})
promises.push(y);
});
Promise
.all(promises)
.then(function (results) {
return plotChart(results); //How do I return this only when it's done below?
}).catch(function (error) {
console.log(error);
});
}
function plotChart(obj){
//do some work with userInfo and return userInfo
return userInfo;
}
Basically onces all fetch are complete and Promise.all runs it calls the plotGraph function that returns a value. How do I return this value only when plotGraph is complete?
Im calling this function from another js page using es6 like this
import {
userRunner
} from './graph'
Any help would be much appreciated.
You can return the promise chain from your component:
export function userRunner(userData) {
return Promise
.all(promises)
.then(function (results) {
return plotChart(results);
})
}
And then continue the chain in the importing file:
import { userRunner } from './graph'
userRunner(userData).then(function (chartedResults) {})

service variable undefined at the time of being accessed in scope

I am trying to implement a controller which has its scope variable being set by service variable like this :
$scope.sidebar= resourceService.sidebar;
The variable sidebar is set by a function called on startup:
var cb = function (api, data) {
for (var key in data) {
var logoArray = data[key];
service.sidebar[key] = logoArray.map(function (logo) {
logo.img = api + "/" + logo.img;
return logo;
});
}
}
service.requestOnStartup = function (api) {
var defer = $q.defer();
$http.get(config.ApiEndpoint.Base + api).success(function (data) {
if (angular.isObject(data)) {
defer.resolve(cb(api, data));
} else {
$log.error("[ResourceService] Unexpected data from resource backend");
defer.reject(data);
}
}).error(function (msg) {
$log.error("Invalid request");
defer.reject(msg);
});
return defer.promise;
};
While the control reaches the scope, the service variable is still not resolved and by the time it is resolved, the control over scope is lost. How do i tackle this problem using promises ?
Your code looks fine if you are displaying $scope.sidebar directly. The variable will be filled asynchronously so it will come after a moment.
If you are doing some action on it while the controller is loading, you'll need to use $watch
$scope.$watch('sidebar', function() {
if ($scope.sidebar) {...} // check for existence here
});
By the way, you can simplify your requestOnStartup like this
service.requestOnStartup = function (api) {
return $http.get(config.ApiEndpoint.Base + api).then(function (data) {
if (angular.isObject(data)) {
return cb(api, data);
} else {
$log.error("[ResourceService] Unexpected data from resource backend");
return $q.reject(data);
}
}, function (msg) {
$log.error("Invalid request");
return $q.reject(msg);
});
};
You can also use the existing $q service of angular js:
service.requestOnStartup = function (api) {
return $q(function(resolve, reject){
$http.get(config.ApiEndpoint.Base + api).then(function (data) {
if (angular.isObject(data)) {
resolve(cb(api, data));
} else {
$log.error("[ResourceService] Unexpected data from resource backend");
reject(data);
}
}, function (msg) {
$log.error("Invalid request");
reject(msg);
});
});
};

deferred promise value not updating/resolving/deferring

I have a controller function that creates something. When the function is called, a setInterval run to get the status of the item.
Here is the service:
(function () {
'use strict';
function myService($q) {
let deferred = $q.defer();
function createSomething(name) {
Meteor.call('createSomething', name, (err, res) {
if (err) {
deferred.reject(err);
} else {
//value returned is the created item (id, name, status)
deferred.resolve(res);
}
});
return deferred.promise;
}
function getStatus(id) {
Meteor.call('getStatus', id, (err, res) {
if (err) {
deferred.reject(err);
} else {
//statuses are queued, processing, created
deferred.resolve(res);
}
});
return deferred.promise;
}
return {
createSomething: createSomething,
getStatus: getStatus
}
}
angular.module('myApp').factory('myService', myService);
})();
And here is the controller:
(function () {
'use strict';
function myController($scope, myService) {
let ctrl = this;
ctrl.create = (name) => {
myService.createSomething(name)
.then((item) => {
ctrl.statusInterval = setInterval(() => {
myService.getStatus(item.data.id)
.then((status) => {
//status is always 'queued' :(
if (status.data.status === 'created') {
clearInterval(ctrl.statusInterval);
//do something
}
});
}, 5000);
});
};
}
angular.module('myApp').controller('myController', myController);
})();
When I check the value of the response in getStatus of the service, the status changes every time it is called (queue -> processing ... processing -> created). However, the value of status in the controller is always queue.
How do I get the promise value to resolve?
createSomething() and getStatus() need to create and return their own promise. They can't share a promise and work properly in all cases.
In addition, they should create and return a unique promise each time they are called, not the same promise every time they are called. Remember, promises are one-way state machines. Once resolved or rejected, their state never changes, even if resolve() or reject() is called again on them.
Here's an example:
function createSomething(name) {
// create a unique deferred inside this function each time you call it
let deferred = $q.defer();
Meteor.call('createSomething', name, (err, res) {
if (err) {
deferred.reject(err);
} else {
//value returned is the created item (id, name, status)
deferred.resolve(res);
}
});
return deferred.promise;
}

service returns promise but cachingService not

I am calling the getWeeklyDates which is calling the cachingGlobalConfigurationService which is again calling the globalConfigurationService if the globalConfiguration data could not be found in the localstorage.
The code =>
return cachingGlobalConfigurationService.getGlobalConfiguration()
.then(function(response1){
works fine when the globalConfiguration is not cached yet because then I make the ajax call and return a promise.
But the above line of code with .then(function(response1) is undefined when my globalConfiguration can be found in the localStorage and just this is returned:
else {
return cachedGlobalConfiguration;
}
I guess I can not use .then in this case but I would like.
How can I fix that?
1
this.getWeeklyDates= function (projectId, currentDate) {
return cachingGlobalConfigurationService.getGlobalConfiguration()
.then(function(response1){
// do business logic
});
2
'use strict';
angular.module('test').service('cachingGlobalConfigurationService', function (localStorageService, globalConfigurationService) {
this.getGlobalConfiguration = function () {
var cachedGlobalConfiguration = localStorageService.get('globalConfiguration');
if (!cachedGlobalConfiguration) {
return globalConfigurationService.getGlobalConfiguration().then(
function (globalConfiguration) {
localStorageService.set('globalConfiguration', globalConfiguration);
return globalConfiguration;
},
function (error) {
console.log('error', error);
});
}
else {
return cachedGlobalConfiguration;
}
};
this.saveGlobalConfiguration = function (globalConfiguration) {
// TODO: Only save to local storage when service.save was successfully
localStorageService.set('globalConfiguration', globalConfiguration);
globalConfigurationService.saveGlobalConfiguration(globalConfiguration);
}
});
3
'use strict';
angular.module('test').service('globalConfigurationService', function ($http) {
this.getGlobalConfiguration = function () {
// TODO get from db
var path = 'scripts/model/globalConfiguration.json';
return $http.get(path).then(function (response) {
return response.data.globalConfiguration;
});
};
this.saveGlobalConfiguration = function (globalConfiguration) {
// TODO: save on db
//var path = 'scripts/model/globalConfiguration.json';
//return $http.post(path, globalConfiguration).then(function (response) {
// alert('global configuration was saved succesfully!');
//});
}
});
You can inject $q service and use $q.when to wrap the object while returning, so that way you are always returning a promise from your api (and just removed the redundant else). Also remember to reject the promise from catch callback of the promise (if required).
'use strict';
angular.module('test').service('cachingGlobalConfigurationService', function (localStorageService, globalConfigurationService, $q) {
this.getGlobalConfiguration = function () {
var cachedGlobalConfiguration = localStorageService.get('globalConfiguration');
if (cachedGlobalConfiguration) {
//Return a promise
return $q.when(cachedGlobalConfiguration);
}
return globalConfigurationService.getGlobalConfiguration().then(
function (globalConfiguration) {
localStorageService.set('globalConfiguration', globalConfiguration);
return globalConfiguration;
},
function (error) {
console.log('error', error);
return $q.reject(error); //<-- reject
});
};
//....
});
$q.when - Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.

Categories