Reputation: 332
I have an AngularJS application, which I use promises to get data from firebase database.
Here is my home-controller
:
$scope.wallets;
walletDAO.getWalletsByUserId(auth.uid)
.then(function(wallets){
$scope.wallets = wallets;
$scope.$apply();
})
.catch(function(error){
console.log(error);
});
These are my two methods inside an service I call walletDAO
:
this.getWalletsByUserId = function(id) {
return new Promise(function(resolve, reject) {
//codigo aqui
var dbRef = database.ref("users/" + auth.currentUser.uid);
dbRef.on('value', function(data) {
//console.log("Wallet IDs Retrieved!");
var userOnDB = data.val();
var walletIds = userOnDB.wallets;
var wallets = [];
for (i = 0; i < walletIds.length; i++) {
var x = getWalletById(walletIds[i])
.then(function(wallet){
wallets.push(wallet);
})
.catch(function(error){
console.log(error);
});
}
resolve(wallets);
}, function(error) {
reject(error);
});
});
};
var getWalletById = function(id) {
return new Promise(function(resolve, reject) {
var dbRef = database.ref("wallets/" + id);
dbRef.on('value', function(data) {
//console.log("Wallet Retrieved!");
var wallet = data.val();
//console.log(wallet);
resolve(wallet);
}, function(error) {
reject(error);
});
});
};
The second method, getWalletById
, receive an wallet ID
and return an wallet
object from the firebase database. this mehod is called on the first method, getWalletsByUserId
inside a for
loop, which should wait for the second method to return the wallet before iterate to the next, so it can push it into the array. The problem is that it dont wait and the code execute the .then()
method on the home-controller
before the resolving of the getWalletById
, leaving the $scope.wallets
empty.
Any advice?
Upvotes: 0
Views: 1239
Reputation: 48968
Instead of manufacturing an ES6 promise from the ref.on method, use the ref.once method and bring it into the AngularJS execution context with $q.when:
function getWalletById(id) {
var dbRef = database.ref("wallets/" + id);
var es6Promise = dbRef.once('value');
return $q.when(es6Promise);
}
Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc.
Use $q.all and promise chaining in the parent function:
this.getWalletsByUserId = function(id) {
var dbRef = database.ref("users/" + auth.currentUser.uid);
var es6Promise = dbRef.once('value')
.then(function(snapshot)
//console.log("Wallet IDs Retrieved!");
var userOnDB = snapshot.val();
var walletIds = userOnDB.wallets;
var promiseList = walletIds.map(function(id){
return getWalletById(id);
});
return $q.all(promiseList);
});
return $q.when(es6Promise);
};
The .then
method returns a new promise which is resolved or rejected via the return value of the successCallback
, errorCallback
(unless that value is a promise, in which case it is resolved with the value which is resolved in that promise using promise chaining).
Upvotes: 1
Reputation: 2528
Use $q.all()
to wait for all sub-promises to complete
$q.all(walletIds.map(function(id){
return getWalletById(id);
})).then(function(wallets){
...
})
Upvotes: 1