Angular $q nested promise - javascript

I have a function that needs to return a list of favorite locations. Something like this
LocationsFactory.getFavoriteLocations().then(function($favoriteLocations) {
});
The getFavoriteLocations looks something like this
getFavoriteLocations: function() {
if (favorite_locations.length == 0)
{
var deff = $q.defer();
obj.getDeviceId().then(function(device_id) {
$http.get('url?token=' + device_id).then(function(response) {
favorite_locations = response.data;
deff.resolve(favorite_locations);
return deff.promise;
})
})
} else {
return favorite_locations;
}
}
The getDeviceId again, it's a function based on promise.
getDeviceId: function() {
var deff = $q.defer();
deff.resolve(Keychain.getKey());
return deff.promise;
}
The error that I got is TypeError: Cannot read property 'then' of undefined. Please help!

You can chain promises:
getFavoriteLocations: function () {
if (favorite_locations.length === 0) {
return obj.getDeviceId().then(function (device_id) {
return $http.get('url?token=' + device_id).then(function (response) {
favorite_locations = response.data;
return favorite_locations;
});
});
}
return $q.resolve(favorite_locations);
}
And improve this:
getDeviceId: function() {
return $q.resolve(Keychain.getKey());
}

$q in not necessary here:
if (favorite_locations.length == 0)
{
return obj.getDeviceId() // you have to return a promise here
.then(function(device_id) {
return $http.get('url?token=' + device_id) // you will access the response below
})
.then(function(response) {
favorite_locations = response.data;
return favorite_locations
});
})
}
Now it should work.

Related

Need help in resolving nested promises, Promises are not getting resolved

I have a service designed which takes some parameter and then loops through input array, and find out which item is empty and then add those to and array and then after $q.all resolved it should give me the array of empty items.
input is array of items
function getElements(inputs) {
var elements= [],
promise, whenPromise,
promises = [],
mainPromise = $q.defer();
if (inputs.length === 0) {
mainPromise.resolve(elements);
return mainPromise.promise;
}
angular.forEach(inputs, function (input) {
promise = getPromises(input);
whenPromise = $q.resolve(promise).then(function (response) {
$timeout(function() {
if (response.isEmpty) {
**//perform action with the response.data;**
}
});
}, function () {
});
promises.push(whenPromise);
});
$q.all(promises).finally(function () {
mainPromise.resolve(outdatedEntities);
});
return mainPromise.promise;
}
function getPromises(input) {
var deferred = $q.defer();
someSerivce.getItemDetails(input.Id).then(function (value) {
if (value === null) {
$timeout(function () {
deferred.resolve({data: input, isEmpty: true});
});
} else {
//have item locally, but need to see if it's current
input.isEmpty().then(function (isEmpty) {
$timeout(function () {
deferred.resolve({data: input, isEmpty: isEmpty});
});
}, function (error) {
deferred.reject(error);
});
}
});
return deferred.promise;
}
Now, the problem is the $q.all is never resolved. Even though all the internal promises are getting resolved.
This should work:
function getElements(inputs) {
var elements = [],
promise, whenPromise,
promises = [],
mainPromise = $q.defer();
if (inputs.length === 0) {
mainPromise.resolve(elements);
return mainPromise.promise;
}
angular.forEach(inputs, function (input) {
promise = getPromises(input);
whenPromise = promise.then(function (response) {
if (response.isEmpty) {
* *//perform action with the response.data;**
}
}, function () {
});
promises.push(whenPromise);
});
return $q.all(promises).finally(function () {
return outdatedEntities;
});
}
function getPromises(input) {
return someSerivce.getItemDetails(input.Id).then(function (value) {
if (value === null) {
return {data: input, isEmpty: true};
} else {
//have item locally, but need to see if it's current
return input.isEmpty().then(function (isEmpty) {
return {data: input, isEmpty: isEmpty};
}, function (error) {
return error;
});
}
});
}

Promise inside promise

I am trying to write this code with Promise. but I don't know how to write promise inside Promise and loop.
I tried to think like this but insertBook function become asynchronously.
How can I get bookId synchronously?
update: function(items, quotationId) {
return new Promise(function(resolve, reject) {
knex.transaction(function (t) {
Promise.bind(result).then(function() {
return process1
}).then(function() {
return process2
}).then(function() {
var promises = items.map(function (item) {
var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
if (item.type === 'book') {
var book = _.pick(item, 'name', 'bookNumber', 'author');
var bookId = insertBook(t, book);
var values = _.merge({}, people, {quotation: quotationId}, {book: bookId});
} else {
var values = _.merge({}, people, {quotation: quotationId});
}
return AModel.validateFor(values);
});
return Promise.all(promises);
}).then(function(items) {
var insertValues = items.map(function (item) {
return People.columnize(item);
});
return knex('people').transacting(t).insert(insertValues);
}).then(function() {
return process5
}).then(function() {
...........
}).then(function() {
t.commit(this);
}).catch(t.rollback);
}).then(function (res) {
resolve(res);
}).catch(function(err) {
reject(err);
});
});
}
function insertBook(t, book){
return Promise.bind(this).then(function () {
return Book.columnizeFor(book);
}).then(function (value) {
return knex('book').transacting(t).insert(value, "id");
});
}
You dont need to get bookid synchronously, you can handle it asynchronously correctly. Also, it is possible you want all book insertions happen sequentially, so I refactored the Promise.all part. (done that just to give you an idea. Promise.all should work fine if insertions in parallel are allowed). Furthermore, I think you shouldn't use Promise.bind. To be honest I dont even know what it does, one thing for sure: it doesn't work with standard promises. So here is an example how I think it should work:
update: function(items) {
return new Promise(function(resolve) {
knex.transaction(function (t) {
resolve(Promise.resolve().then(function() {
return process1;
}).then(function() {
return process2;
}).then(function() {
var q = Promise.resolve(), results = [];
items.forEach(function (item) {
q = q.then(function() {
var book = _.pick(item, 'name', 'bookNumber', 'author');
return insertBook(t, book);
}).then(function(bookId) {
var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
var values = _.merge({}, people, {book: bookId});
return AModel.validateFor(values);
}).then(function(item) {
results.push(item);
});
});
return q.then(function() {
return results;
});
}).then(function(items) {
return process4
}).then(function() {
t.commit(result);
}).catch(function(e) {
t.rollback(e);
throw e;
}));
});
});
}
function insertBook(t, book){
return Promise.resolve().then(function () {
return Book.columnizeFor(book);
}).then(function (value) {
return knex('book').transacting(t).insert(value, "id");
});
}
Assuming that insertBook returns a promise you could do
var people = _.pick(item, 'familyName', 'firstNumber', 'tel');
if (item.type === 'book') {
var book = _.pick(item, 'name', 'bookNumber', 'author');
return insertBook(t, book)
.then(bookId => _.merge({}, people, {quotation: quotationId}, {book: bookId}))
.then(AModel.validateFor)
} else {
return Promise.resolve(_.merge({}, people, {quotation: quotationId}))
.then(AModel.validateFor)
}

AngularJS and Restangular: TypeError: Cannot read property 'then' of undefined

I built a service and this service return an object. But, in my controller i don't work with this object because '.then' dont't work.
My service:
var getUser = function(userId) {
Restangular.all(userId).post(JSON.stringify()).then(function(response) {
var obj = angular.fromJson(response);
if (!obj.isError) {
return obj;
}
else {
console.log("ERRO getUserCard");
}
});
};
My controller:
var succsess = function(data){
welcomeScope.getUser = data;
console.log("getUser: " + welcomeScope.getUser);
};
var error = function(){
console.log("Erro error");
};
function loadProfile(){
welcomeSvc.getUser("203831").then(success,error);
};
Note: welcomeScope is my $scope.
you should add return in function getUser
var getUser = function(userId){
return Restangular.all(userId).post(JSON.stringify()).then(function(response){
var obj = angular.fromJson(response);
if (!obj.isError) {
return obj;
}
else{
console.log("ERRO getUserCard");
}
});
};
Your getUser() function needs to return a promise:
var getUser = function(userId) {
return new Promise(function(resolve, reject) {
Restangular.all(userId).post(JSON.stringify()).then(function(response) {
var obj = angular.fromJson(response);
if (!obj.isError) {
resolve(obj);
}
else {
reject(console.log("ERRO getUserCard"));
}
})
})
};
You may need to pass resolve, reject into Restangulars promise

Looping with Promises

I'm in a scenario where I have to get data from the server in parts in sequence, and I would like to do that with the help of Promises. This is what I've tried so far:
function getDataFromServer() {
return new Promise(function(resolve, reject) {
var result = [];
(function fetchData(nextPageToken) {
server.getData(nextPageToken).then(function(response) {
result.push(response.data);
if (response.nextPageToken) {
fetchData(response.nextPageToken);
} else {
resolve(result);
}
});
})(null);
});
}
getDataFromServer().then(function(result) {
console.log(result);
});
The first fetch is successful, but subsequent calls to server.getData() does not run. I presume that it has to do with that the first then() is not fulfilled. How should I mitigate this problem?
Nimrand answers your question (missing catch), but here is your code without the promise constructor antipattern:
function getDataFromServer() {
var result = [];
function fetchData(nextPageToken) {
return server.getData(nextPageToken).then(function(response) {
result.push(response.data);
if (response.nextPageToken) {
return fetchData(response.nextPageToken);
} else {
return result;
}
});
}
return fetchData(null);
}
getDataFromServer().then(function(result) {
console.log(result);
})
.catch(function(e) {
console.error(e);
});
As you can see, recursion works great with promises.
var console = { log: function(msg) { div.innerHTML += "<p>"+ msg +"</p>"; }};
var responses = [
{ data: 1001, nextPageToken: 1 },
{ data: 1002, nextPageToken: 2 },
{ data: 1003, nextPageToken: 3 },
{ data: 1004, nextPageToken: 4 },
{ data: 1005, nextPageToken: 0 },
];
var server = {
getData: function(token) {
return new Promise(function(resolve) { resolve(responses[token]); });
}
};
function getDataFromServer() {
var result = [];
function fetchData(nextPageToken) {
return server.getData(nextPageToken).then(function(response) {
result.push(response.data);
if (response.nextPageToken) {
return fetchData(response.nextPageToken);
} else {
return result;
}
});
}
return fetchData(0);
}
getDataFromServer().then(function(result) {
console.log(result);
})
.catch(function(e) { console.log(e); });
<div id="div"></div>
Because your then statement doesn't pass a function to handle error cases, requests to the server for data can fail silently, in which case the promise returned by getDataFromServer will never complete.
To fix this, pass a second function as an argument to then, as below:
function getDataFromServer() {
return new Promise(function(resolve, reject) {
var result = [];
(function fetchData(nextPageToken) {
server.getData(nextPageToken).then(function(response) {
result.push(response.data);
if (response.nextPageToken) {
fetchData(response.nextPageToken);
} else {
resolve(result);
}
}).catch(function(error) {
//Note: Calling console.log here just to make it easy to confirm this
//was the problem. You may wish to remove later.
console.log("Error occurred while retrieving data from server: " + error);
reject(error);
});
})(null);
});
}

Angular Directive Follow/Unfollow button

I'm trying to make angular directive button to follow and unfollow leagues ID
every request $http.put going fine but there is a problem with .then method console show me error and the method rejected
here the code
app.factory('FollowedLeagues', ['appConfig', '$http', '$q', function(appConfig, $http, $q){
var FollowedLeagues = {};
FollowedLeagues.follow = function (token, leagueID) {
$http.put(appConfig.apiUrl + 'user/follow-league?token=' + token +'&league_id='+ leagueID +'&status=true' )
.then(function(response){
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
},
function(response) {
// something went wrong
return $q.reject(response.data);
});
};
FollowedLeagues.unfollow = function (token, leagueID) {
$http.put(appConfig.apiUrl + 'user/follow-league?token=' + token +'&league_id='+ leagueID +'&status=false' )
.then(function(response){
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
},
function(response) {
// something went wrong
return $q.reject(response.data);
});
};
return FollowedLeagues;
}]);
app.directive('fbFollowBtn', ['$rootScope', '$compile', 'FollowedLeagues', function ($rootScope, $compile, FollowedLeagues) {
var getLeagueID = function(leagueID, followed){
for(var i=0; i< followed.length; i++) {
var fLeagues = followed[i]._id;
if (fLeagues == leagueID) {
return fLeagues;
}
}
};//End-function.
return {
restrict: 'A',
link:function(scope, element, attrs){
scope.followed = $rootScope.meData.followedLeagues;
scope.leagueid = attrs.leagueid;
var follow_btn = null;
var unfollow_btn = null;
var createFollowBtn = function () {
follow_btn = angular.element('Follow');
$compile(follow_btn)(scope);
element.append(follow_btn);
follow_btn.bind('click', function(e){
scope.submitting = true;
FollowedLeagues.follow($rootScope.userToKen, scope.leagueid)
.then(function(data){
scope.submitting = false;
follow_btn.remove();
createUnfollowBtn();
console.log('followed Leagues Done :-) ', data);
});
// scope.$apply();
});
};
var createUnfollowBtn = function () {
unfollow_btn = angular.element('Unfollow');
$compile(unfollow_btn)(scope);
element.append(unfollow_btn);
unfollow_btn.bind('click', function (e) {
scope.submitting = true;
FollowedLeagues.unfollow($rootScope.userToKen, scope.leagueid)
.then(function(data){
scope.submitting = false;
unfollow_btn.remove();
createFollowBtn();
console.log('followed Leagues Done :-) ', data);
});
// scope.$apply();
});
};
scope.$watch('leagueid', function (val) {
var leag = getLeagueID(scope.leagueid, scope.followed);
if(typeof(leag) == 'undefined'){
createFollowBtn();
} else if(typeof(leag) !== 'undefined'){
createUnfollowBtn();
}//end if
}, true);
}
};
}]);
You have to return your $http.put function inside your service functions. For example the Followedleagues.follow function:
FollowedLeagues.follow = function (token, leagueID) {
return $http.put(appConfig.apiUrl + 'user/follow-league?token=' + token +'&league_id='+ leagueID +'&status=true' )
.then(function(response){
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
},
function(response) {
// something went wrong
return $q.reject(response.data);
});
};

Categories

Resources