Combining 2 promises in angularjs - javascript

Im combining 2 promises but isnt working, in a service i have 2 methods, where the method "UserService.getAuthenticatedUser()" gets the current user information and than there is a "UserService.getAccountTypeData(idUser)", where gets the usertype information, but to get to the second method i need the userID, so basically first i call the "UserService.getAuthenticatedUser()", get the id, and than call "UserService.getAccountTypeData(idUser)", but isnt working.
function isAccount(accountName) {
UserService.getAuthenticatedUser()
.then(function (response) {
var userDetails = response.data;
});
UserService.getAccountTypeData(idUser)
.then(function (response) {
var userDetails = response.data;
return userDetails;
});
}
PS: I already injected the service...

You can chain your promises by returning values from your .then() functions.
function isAccount(accountName) {
return UserService.getAuthenticatedUser(accountName) // pass in accountName argument?
.then(function(response) {
var userDetails = response.data;
return userDetails.Id; // user id value
})
.then(UserService.getAccountTypeData) // userDetails.Id gets passed to getAccounttypeData method
.then(function(response) {
var userDetails = response.data;
return userDetails;
});
}
// usage
isAccount('AccountA').then(function(userDetails) {
// do something with userDetails
});

You're dealing with asynchronous calls, so when you call the .then() method, it's executing the function and wiring up the callback to an anonymous function passed as a parameter to then(). If the second is dependent on the first, you could nest them like this...
function isAccount(accountName) {
UserService.getAuthenticatedUser()
.then(function (response) {
var userDetails = response.data;
UserService.getAccountTypeData(idUser)
.then(function (response) {
var userDetails = response.data;
return userDetails;
});
});
}

Related

Using a value from a get with ngResource in the controller

I'm struggling with using the value that I got from a 'get' in my controller.
This is my code in my controller
vm.user;
function onInit(){
loadUser(vm.queryParams.id[0]);
console.log(vm.user);
}
function loadUser(UserId) {
var defer = $q.defer();
User.get({ id: userId }).$promise.then(function (user) {
vm.user = user;
defer.resolve();
});
return defer.promise;
};
When I print the vm.user in the onInit() it is undefined. While when I look on the view where vm.user is called it just shows me the correct values of the user. So it's not known after the loadUser() in the controller but it is in my view.
I would like to first 'get' the user and then use it for further logic in the onInit(). How to retrieve the user properly so I can further use it and call its values in the onInit()?
You have to wait till the execution of loadUser() is finished so as the get the value of user.You can use the promise returned like this and do any calcualtions on it.
vm.user;
function onInit(){
var promise=loadUser(vm.queryParams.id[0]);
promise.then(function(response){
console.log(response);
});
}
function loadUser(UserId) {
var defer = $q.defer();
User.get({ id: userId }).$promise.then(function (user) {
vm.user = user;
defer.resolve(vm.user);
});
return defer.promise;
};
Immediately invoke your init function at the beginning of your controller and convert your loadUser function to a service since its a get action. Your service will return the user which you can then set.
(Declare at top of controller):
init();
function init(){
loadUserService.loadUser(UserId)
.then(function (user) {
vm.user = user;
defer.resolve();
})
}

AngularJS factory returning State object instead of JSON data from promise

I have made two factory and calling first from second one, consuming second one factory in controller but instead of getting data as JSON, I'm getting data as $$State.
I'm new to angularJS tried many ways but not able to solve, please help.
app.factory('userDetails', ['APIService', '$q', function (APIService, $q) {
getDetails: function () {
var deferred = $q.defer();
var getFunc = function () {
APIService.doGetCall('Masters/employee/username/tarun')
.then(
function (data)
{
deferred.resolve(data);
},
function (data, status, headers, config)
{
deferred.reject('There was an error creating object'); })
return deferred.promise;
}
var a = getFunc();
return a;
}
}
vm.user = userDetails.getDetails();
console.log("user",vm.user);
response is as per below snippet
Response
You should be using .then function to get response there. Rather I'd say you don't need to create extra promise, its an anti-pattern. Where you could utilize the promise return by doGetCall method directly.
app.factory('userDetails', ['APIService', '$q', function(APIService, $q) {
getDetails: function() {
var getFunc = function() {
return APIService.doGetCall('Masters/employee/username/tarun');
}
var a = getFunc();
return a;
}
}]);
vm.user = userDetails.getDetails().then(function(response){
console.log(response.data);
vm.user = response.data;
console.log("user", vm.user);
}, function(error){
console.log(error)
}).catch(exceptionHandler);
userDetails.getDetails() returns a promise, Hence you need to use .then(onsuccess, onRejected)
userDetails.getDetails().then(function(data){
vm.user = data;
console.log("user",vm.user);
});
You've got the
return deferred.promise;
line inside the APIService.doGetCall function. It should be outside of it.

AngularJS - return promise success value to the calling function

I am learning AngularJS and AJAX.I am trying to assign the data being returned by the success function to user. grantRole belongs to Auth service. The value of user as I currently have it is a promise. How do I assign the returned data on success to user?
$scope.grantRole = function(user) {
user = Auth.grantRole(user).then(
function success(data){
return data;
},
function error(err){
console.log(err);
}
);
grantRole: function(user,callback) {
var cb = callback || angular.noop;
var data = {id: user._id,controller:'role'};
return User.update({id: user._id,controller:'role'},data,
function(user) {
return cb(user);
}, function(err) {
return cb(err);
}).$promise;
};
The current value of user being a promise is correct. Once the promise gets resolved, it will be assigned to the data returned on success.
But you have to be careful when reassigning objects or arrays. See Service variable not updating in controller
E.g., don't do this: user = ...;
Rather, do this: angular.copy(newInfo, user) or this: user.email = ...
$scope.grantRole = function(user) {
Auth.grantRole(user).then(
function success(data){
angular.copy(data, user);
},
function error(err){
console.log(err);
}
);

angular, correct way for a function callback

I am writing an ItemProvider for my app in angular js.
I chose a service.
app.factory('ItemProvider', function($http) {
var url = "http://localhost:7888/api.php/json?";
return {
get_data: function() {
$http.get(url).
success(function(data,status,headers,config) {
json = data;
console.log("app returned ok");
console.log(json);
callback(json);
}).
error(function(data,status,headers,config) {
console.log("Error getting data from app!");
json = data;
callback(json);
});
callback = function(json) {
console.log("callback");
return json;
}
console.log("already done");
}
};
});
Of course what happens here is that get_data returns immediately before the actual calls to the backend via $http returned...
How do I correctly have a get_data function which will return the data from the backend? I tried adding a callback (see code above) but I realize by the time it's getting called, get_data already finished as well...
$http is hardcoded to only work asynchronously, meaning your only option is to code with that in mind. Due to this, it isn't possible for get_data to directly return the data, instead, it has to either accept a callback, or return a promise. The promise route is far easier in my opinion.
app.factory('ItemProvider', function($http) {
var url = "http://localhost:7888/api.php/json?";
return {
get_data: function(url) {
return $http.get(url);
}
};
});
example usage:
//...
ItemProvider.get_data('/items')
.success(function (items) {
console.log(items);
})
.error(function () {...});
//...

Chaining multiple promises (handling callbacks)

I am having some difficulties with promises when it comes chaining multiple ones. The confusion is distinguishing how to properly take advantage of promises & their difference with Callbacks. I noticed that callbacks sometime fire regardless a promise is resolved or not, making the below implementation unreliable..(Unless my syntax & logic are wrong) I read the official documentation and came up with this, but I am not sure it is well implemented.The Registration flow is as follow:
User chooses an Alias -> Details Alias + userID (Device's Universally Unique Identifier) are sent server side
If Alias is available, ApiKey(token) is generated, User registered and sent back client side (Stored in DB)
Services.js
(function(angular) {
myApp.factory("deviceDB.Service", ['$resource', '$http', '$q',
function ($resource, $http , $q ) {
return {
//Second Promsie : After API token is generated server-side, store res in db
RegDevice: function (alias, apiKey, userID) {
var deferred = $q.defer();
var configuration ;
var db = window.sqlitePlugin.openDatabase({name: "config.db"});
setTimeout(function () {
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS user_details (userID UNIQUE , alias TEXT, apiKey TEXT)');
tx.executeSql("INSERT INTO user_details (userID, alias, apiKey) VALUES (?,?,?)", [userID, alias, apiKey], function (tx, res) {
deferred.resolve(configuration = true);
}, function (e) {
// console.log("ERROR: " + e.message);
deferred.reject(configuration = false);
});
});
}, 1000);
return deferred.promise;
},
//First Promsie: Register user server side & generate APi token
RegUser: function (alias, userID) {
var deferred = $q.defer();
var pro;
pro = $resource('api/query/register', {'alias': alias, 'userID': userID},
{ query: {
isArray: false,
method: 'GET' } });
setTimeout(function () {
pro.query(function (res) {
if (res.error) {
deferred.reject( { error : res.error, exists: res.exists, msg: res.message } );
}
else {
deferred.resolve( {error : res.error , alias: res.alias , apiKey: res.apiKey, msg: res.message } );
}
}, function (e) {
deferred.reject( { errorStatus: e.status } );
});
}, 1000);
return deferred.promise;
}
};
}]);
}(window.angular));
Now, in My controller I would like to chain both promises above. I quote the follwoing from the Documentation :
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.
What is the point of having Callbacks if they can fire regardless if the Promise is resolved?
Shouldn't I call for e.g Promise2 within the first Promise's Success Callback? If it is fired regardless of of Promise1 being resolved, How then can I chain Promise2 in a way to fire only when Promise1 is resolved?
What I tried :
Controller.js
myApp.controller('RegisterController', ['$scope', '$http', 'deviceDB.Service',
function ($scope , $http , deviceDB.Service) {
var Promise1 = deviceDB.RegUser($scope.alias, $scope.Device);
// First promise - Validate with server
Promise1.then(function(data)
{
console.log(' Registration Server-Side successfully');
$scope.apiKey = data.apiKey;
term.echo(data.apiKey);
}, function(e)
{
console.log('Registration Failed');
term.echo(e.msg);
})
//Call Promise 2 & Store details Client-Side using .then()
.then(deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device),
function(d){
console.log('Items Stored in DB successfully');
}, function()
{
console.log('Items Stored in DB Failed');
});
}]);
Notes: I understand it is a bad practice to store details client-side, however, i am after a different concept (anonymous messaging) and there is no security concerns..
Thanks for your time
Your second then call seems incorrect, after
//Call Promise 2 & Store details Client-Side using .then()
then takes up-to 3 parameters then(successCallback, errorCallback, notifyCallback) you are passing it: deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device) which is evaluated immediately and the promise returned is passed to the function then as the success function, your success function is passed as the errorCallback and your fail function is passed as the notifyCallback.
I would try the following
Promise1.then(function(data)
{
console.log(' Registration Server-Side successfully');
$scope.apiKey = data.apiKey;
term.echo(data.apiKey);
return deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device)
}, function(e)
{
console.log('Registration Failed');
term.echo(e.msg);
return e;
}).then(function(d) {/*all good*/}, function(e) {/* all bad */}
Notice the call to RegDevice is now within a function block, and a promise is returned from the then block you want to chain from.
I find $q.serial a great library for chaining promises. It's very easy to use and handles a lot of stuff like checking if all promises on the chain are really promises.
Here is a small example:
function do_all() {
var task_1 = function() {
return $http.get("some url")
.then(on_xhr_completed_fn, on_xhr_failed_fn);
}
var task_2 = function(some_data) {
vm.bla = some_data;
return $http.get("other url")
.then(on_xhr_completed_fn, on_xhr_failed_fn);
}
var task_3 = function(other_data) {
vm.bli = other_data;
}
var tasks = [task_1, task_2, task_3];
return $q.serial(tasks)
.then(function() {
console.log("Finished tasks 1, 2 and 3!!!");
});
}
Here's an approach that may be helpful using async/await:
async function run_promise_A(args) {
return new Promise((resolve, reject) => {
return resolve(resolve_value)
});
}
async function run_promise_B(args) {
return new Promise((resolve, reject) => {
return resolve(resolve_value)
});
}
async function run_promise_C(args) {
return new Promise((resolve, reject) => {
return resolve(resolve_value)
});
}
async function run_several_async_functions(userid) {
let a = run_promise_A(userid);
let b = run_promise_B(a);
let c = run_promise_C(b);
return c;
}
return Promise.resolve()
.then(() => {
let c = (async () => {
let c = await run_several_async_functions(userid)
return c;
})();
return c;
})
.then((c) => {
return c;
})
.catch((err) => {
console.log(err);
});

Categories

Resources