Using nested $http.get calls in Angular JS sequentially - angularjs

I have this situation where two $http.get calls are nested.I get result from the first call and then iterating over this first result and passing this to another $http.get call and in the end I amtrying to make whole thing as ab array of objects.I am finding that ,this whole is not happening in sequence.Could someone help me out?
$scope.populateData = function()
{
$scope.infoWithStatus = [];
$http.get("commonAppGet.jsp?sqlStr=select name from test where title_id=1").then(function(resp){
$scope.names = resp.data.d;
for(var i=0;$scope.names.length;i++){
infoObject= {};
var c1=0;c2=0; c3=0;c4=0;c5=0;
$scope.spocName = $scope.names[i].name;
infoObject.name=$scope.spocName;
$http.get("commonAppGet.jsp?sqlStr=select a.status as status from test1 where name='"+$scope.spocName+"'").then(function(resp){
$scope.statusValues = resp.data.d;
for(var i=0;i<$scope.statusValues.length;i++)
{
if($scope.statusValues[i].status==0)
c1++;
if($scope.statusValues[i].status==1)
c2++;
//some code for c3,c4,c5
}
infoObject.count1=c1;
infoObject.count2=c2;
infoObject.count3=c3;
infoObject.count4=c4;
infoObject.count5=c5;
});
$scope.infoWithStatus.push(infoObject);
}
});
}

Maybe this will be you
I saw that you missing i < $scope.names.length in the first promise
$scope.populateData = function()
{
$scope.infoWithStatus = [];
var c1=0;c2=0; c3=0;c4=0;c5=0;
$http.get("commonAppGet.jsp?sqlStr=select name from test where title_id=1").then(function(resp){
$scope.names = resp.data.d;
var listPromise = [];
for(var i=0;i < $scope.names.length;i++){
infoObject= {};
$scope.spocName = $scope.names[i].name;
infoObject.name=$scope.spocName;
listPromise.push($http.get("commonAppGet.jsp?sqlStr=select a.status as status from test1 where name='"+$scope.spocName+"'"));
$scope.infoWithStatus.push(infoObject);
}
return Promise.all(listPromise);
}).then(function(resp){
for (var i = 0; i < resp.length; i++) {
$scope.statusValues = resp[i].data.d;
for(var i=0;i<$scope.statusValues.length;i++)
{
if($scope.statusValues[i].status==0)
c1++;
if($scope.statusValues[i].status==1)
c2++;
//some code for c3,c4,c5
}
infoObject.count1=c1;
infoObject.count2=c2;
infoObject.count3=c3;
infoObject.count4=c4;
infoObject.count5=c5;
}
});
}

Related

AngularFire (AngularJS) voting app cant iterate over firebase data

I am using ng-repeat to print array data from Firebase. As seen below; foreeach quote I want to count all the votes assosiated with it but any attempt to iterate results in undefined
my Markup
<div ng-repeat="q in quotes" ng-init="total_votes(q)">
{{q.name}}
</div>
my controller
app.controller('account', function ($scope, $timeout, $rootScope, $location, $firebaseObject, $firebaseArray) {
//======== Get Quotes ========//
var ref = firebase.database().ref().child('quotes');
$scope.quotes_obj = $firebaseObject(ref);
$rootScope.quotes = $firebaseArray(ref);
//======== item totals ========//
$scope.total_votes = function(itm) {
// attempt ONE
var itm_votes = $scope.quotes_obj[itm.$id].votes;
console.log(itm_votes); // returns "{-KzFkQYHWKwbAPjIekWz: "sad", -KzLT76T14doKgYbjRc1: "wow"}"
console.log(itm_votes.length); // returns "undefined"
// attempt TWO
console.log(itm.votes) // returns "{-KzFkQYHWKwbAPjIekWz: "sad", -KzLT76T14doKgYbjRc1: "wow"}"
console.log(itm.votes[0]) // returns "undefined"
console.log(itm.votes.length) // returns "undefined"
// count votes
var counts = {};
for (var i = 0; i < itm_votes.length; i++) {
counts[itm_votes[i]] = 1 + (counts[itm_votes[i]] || 0);
if(i == itm_votes.length){
console.log('done');
}
}
return counts;
};
});
Here is a picture of a single quote on my firebase database
Does anyone know why the index is undefined for the data? I am open to new ways to count all the like votes if you see something wrong with this approach
anything helps. Thanks!
I had to $.map to convert the obj to array.
$scope.total_votes = function(itm) {
var itm_votes = $.map($scope.quotes_obj[itm.$id].votes, function(value, index) {
return [value];
});
console.log(itm_votes.length);
var counts = {};
for (var i = 0; i < itm_votes.length; i++) {
counts[itm_votes[i]] = 1 + (counts[itm_votes[i]] || 0);
if(i == itm_votes.length-1){
console.log('done');
console.log(counts);
}
}
return counts;
};

How to set factory properties so they are independent from one another?

Consider the below Angularjs 'service'. I would like to keep all my 'entries' related variables in this service so I can use them across controllers - as I believe the ideal angular pattern calls for. However, if I manipulate anyone of the variables from a controller - entries, entries_Sorted, entries_Loaded within the service object - they all seem to take on the same new value. I understand the factory object is a singleton but shouldn't these variables be independent? I don't expect or understand the behavior I am seeing. How is this useful? I must be doing something wrong.
To be clear:
If I set local variables within my controllers using this service's return methods, then update those local variables, all the three entries variables within the service will take on the new values.
Service code:
angular.
module('core.entry').
factory('Entry', ['$http', 'Topten', 'Stack', 'User',
function($http, Topten, Stack, User) {
var entries = [];
var entries_Sorted = [];
var entries_Loaded = [];
var service = {};
service.getEntries = function(stackId, callback) {
return $http.get('stacks/' + stackId + '/entries/')
.success(function(data) {
entries = data["entries"];
Topten.setToptens(data["topTen"]);
Stack.setOpenStack(data["stack"]);
callback(null, data);
})
.error(function(err) {
callback(err, null);
});
};
service.returnEntries = function() {
return entries;
}
service.sortEntries = function(callback) {
// 1. Loop through entries inner looping on toptens - adding topten score to total score
for (var i = 0; i < entries.length; i++) {
var thisEntry = entries[i];
var totalScore = 0;
var toptens = Topten.returnToptens();
for (var j = 0; j < toptens.length; j++) {
var thisTopten = toptens[j];
if (thisTopten["entryId"]) {
if (thisEntry["_id"] == thisTopten["entryId"]._id) {
totalScore = totalScore + thisTopten["score"];
}
}
}
thisEntry.totalScore = totalScore;
// 2. Add net (likes - dislikes) to entry.totalScore
for (var j = 0; j < thisEntry.votes.length; j++) {
var thisVote = thisEntry.votes[j]["vote"];
if (thisVote == "up") {
thisEntry["up"] = thisEntry["up"] + 1;
} else if (thisVote == "down") {
thisEntry["down"] = thisEntry["down"] + 1;
}
}
var netLikes = thisEntry["up"] - thisEntry["down"]; // one point each
thisEntry["totalScore"] = thisEntry["totalScore"] + netLikes;
}
// 3. Sort entries by entry.totalScore and return
entries_Sorted = entries.sort(function(a, b) {
return b.totalScore - a.totalScore;
});
callback();
};
service.returnEntries_Sorted = function() {
return entries_Sorted;
};
return service;
}
]);
My controller's code:
Entry.getEntries($routeParams.stackId, function(err, data) {
if(err) {
}
// get sorted entries (after return from getEntries)
Entry.sortEntries(function() {
self.entries_Sorted = Entry.returnEntries_Sorted();
self.loadMore();
});
});
self.loadMore = function() {
self.entries_Loaded = self.entries_Loaded.concat(self.entries_Sorted.splice(page * increment, increment));
self.page +=1;
}
Problem: After I call this local 'load_More' function, the properties in my service - entries, _Sorted, _Loaded - will all have the new 'spliced' value. ie. Entry.entries will have the same value as the controller's local self.entries_Sorted.

AngularJS - getting asynchronous data back from a factory to use in a controller

The issue I'm having is that I'm trying to get data from my factory to my controller in time for the controller to access that data. Currently, when I console log out the data, I get an empty object, but if I examine the data further I get the whole "value was snapshotted, but here it is live" in Chrome.
Here's my Factory, called DataService:
var data = {};
var firstPillarData = {};
var secondPillarData = {};
var thirdPillarData = {};
firstPillarData.ourArray = [];
secondPillarData.ourArray = [];
thirdPillarData.ourArray = [];
function userRetrievalSuccess(response){
console.log('userRetrievalSuccess', response.data);
data.users = response.data;
console.log('data.users is', data.users);
console.log('and the data object is', data);
for(var i = 0; i < data.users.length; i++){
if(data.users[i].initiatives != null){
console.log("we have initiatives for this user", data.users[i]);
for(var j = 0; j < data.users[i].initiatives.length; j++){
switch(data.users[i].initiatives[j].pillar){
case 1:
firstPillarData.ourArray.push(data.users[i].initiatives[j]);
break;
case 2:
secondPillarData.ourArray.push(data.users[i].initiatives[j]);
break;
case 3:
thirdPillarData.ourArray.push(data.users[i].initiatives[j]);
break;
default:
break;
}
}
}
}
data.firstPillarData = firstPillarData;
data.secondPillarData = secondPillarData;
data.thirdPillarData = thirdPillarData;
console.log("our data.firstPillarData is", data.firstPillarData);
console.log("our data.secondPillarData is", data.secondPillarData);
console.log("our data.thirdPillarData is", data.thirdPillarData);
return data;
}
function userRetrievalFail(){
console.log('error retrieving users');
}
function getAllUserData(){
$http.get('/kpi/allUsers/').then(userRetrievalSuccess, userRetrievalFail)
}
And here's where it's being called in my controller:
DataService.getAllUserData();
var data = DataService.data;
I thought that using the .then method on the $http.get would handle my issue, but it clearly isn't. What am I doing wrong?
It turns out that adding a second promise/.then on the controller side took care of my issues. But thanks to #JB-Nizet and #Ladmerc for the help!

AngularJS - create object array where label is $translated

I have the following array:
vm.roles = ['ROLE1', 'ROLE2', 'ROLE3', 'ROLE4'];
and I need this form of array:
vm.translatedRoles = [{id:0, label:'Role1'}, {id:1, label:'Role2'}, ...]
Therefore I wrote this function to transfer from vm.roles to vm.translatedRoles.
My Problem now is that translatedRoles stays empty, so there are no objects in it. Does anyone know why?
function translateRoles() {
var translatedRoles = [];
for(var i = 0; i < vm.roles.length; i++) {
$translate(vm.roles[i]).then(function(text) {
var role = {};
role.id = i;
role.label = text;
translatedRoles.push(role);
});
}
return translatedRoles;
}
That can't work. $translate() returns a promise. The function passed to $translate is executed later, asynchronously, when the translations are available. So, the return statement happens before translatedRoles is populated by the function.
You need to return a promise of array, or hope that the translations are already available and use $translate.instant():
function translateRoles() {
var translatedRoles = [];
for (var i = 0; i < vm.roles.length; i++) {
translatedRoles.push({
id: i,
label: $translate.instant(vm.roles[i]);
});
}
return translatedRoles;
}

$http in loop, wait the results

I have this :
var j = 0;
// myList.length = 3
while(j < self.myList.length - 1){
$http.post('myURL', self.myList[j].code).then(
function(response){
self.myList[j].plop = response.data;
}, function(){
// error
}
).then(
function(){
// with this j++, my web page is freezing
// j++;
}
);
// with this j++, only the 3rd element of myList have a "plop" element
//j++;
}
My problem is in comments :) for "j++".
If I remove the loop while and hardcoded the 3 step, it's working. But I don't know how to solve the issue with a loop. Do you have an idea ? Thanks
Synchronized solution according to OP's comment:
var promises = [];
for(var i=0;i<self.myList.length;i++)
promises.push($http.post(...));
$q.all(promises).then(function(results){
//All results available here
var data = results.map(result => result.data);
data.forEach((e, idx) => self.myList[idx] = e);
})
.catch(function(e){
//Handle error
});
Issue is
$http.post().then(function(){}, function(){}) is asynchronous function. So .then() method will be executed when loop is completed. This is the reason it always takes last value of j that is 2.
then() will come only one time with $http.post() so remove second .then()
Solution posted below:
var j = 0;
var i = 0;
// myList.length = 3
while(j < self.myList.length - 1){
$http.post('myURL', self.myList[j].code).then(function(response){
self.myList[i].plop = response.data;
i++;
}, function(){
// error
}
);
}

Resources