AngularFire (AngularJS) voting app cant iterate over firebase data - angularjs

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;
};

Related

Using nested $http.get calls in Angular JS sequentially

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;
}
});
}

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.

how to access function parameter value inside nested AngularJS for each loop?

I am new for AngularJS and I am trying to access function parameter value inside nested angular for each loop , but that variable gets undefined error. here is my code .
var pieChart = function (_data, _fieldName) {
var data = _data;
var cost_max = 0;
var cost_min = 99999;
angular.forEach(groupBy($scope.api_data, _fieldName), function (obj, index) {
var total = 0;
var name = '';
angular.forEach(obj, function (row, i) {
name = row._fieldName;
total += 1;
})
data.push([name, total]);
if (cost_max < obj.cost) cost_max = obj.cost;
if (cost_min > obj.cost) cost_min = obj.cost;
})
$scope.chart.data = data;
$scope.loaded = 1;
}
row._fieldName is undefined here , what was the issue ? kindly help me.
var groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
In your second angular.forEach loop, you have to replace row._fieldName with row[_fieldName].
angular.forEach(obj, function (row, i) {
name = row[_fieldName];
total += 1;
})
By writing row._fieldName, you try to get the key named _fieldName from object row instead of the real field.
Little JSFiddle

make filter based on data from localstorage in the filter function

I'm new with the Ionic-angular.js, I hope that someone will help me to resolve this problem
First, here is the code
favorites.html
...
<ion-item ng-repeat="dish in dishes | favoriteFilter:favorites" href="#/app/menu/{{dish.id}}" class="item-thumbnail-left" on-swipe-left="deleteFavorite(dish.id)">
<img ng-src="{{baseURL+dish.image}}" on-swipe-left="deleteFavorite(dish.id)">
<h2>{{dish.name}}
<ion-delete-button class="ion-minus-circled"
ng-click="deleteFavorite(dish.id)">
</ion-delete-button>
</ion-item>
...
services.js
.factory('favoriteFactory', ['$resource', 'baseURL', function ($resource, baseURL) {
var favFac = {};
var favorites = [];
favFac.addToFavorites = function (index) {
for (var i = 0; i < favorites.length; i++) {
if (favorites[i].id == index)
return;
}
favorites.push({id: index});
};
favFac.deleteFromFavorites = function (index) {
for (var i = 0; i < favorites.length; i++) {
if (favorites[i].id == index) {
favorites.splice(i, 1);
}
}
}
favFac.getFavorites = function () {
return favorites;
};
return favFac;
}])
.factory('$localStorage', ['$window', function($window) {
return {
store: function(key, value) {
$window.localStorage[key] = value;
},
get: function(key, defaultValue) {
return $window.localStorage[key] || defaultValue;
},
storeObject: function(key, value) {
$window.localStorage[key] = JSON.stringify(value);
},
getObject: function(key,defaultValue) {
return JSON.parse($window.localStorage[key] || defaultValue);
}
//removeItem: function(key){
// $window.localStorage.removeItem(key);
//}
}
controller.js
.filter('favoriteFilter', 'localStorage', function (localStorage) {
if(localStorage.getItem('favorites')!=undefined)
{
var out = [];
return out;
}
else{
return function (dishes) {
var old_favorite = JSON.parse($localStorage.get('favorites'));
var leng = Object.keys(old_favorite).length;
console.log(leng);
var out = [];
for (var i = 0; i < leng; i++) {
for (var j = 0; j < dishes.length; j++) {
if (dishes[j].id === favorites[i].id)
out.push(dishes[j]);
}
}
return out;
}}
});
For the example, there was an array inside the localstorage like this
Key : favorites
value : [{"id":1},{"id":2},{"id":0}]
So, the logic is, I compare the ID between from database and the localstorage based on the ID with the filter function
If the ID is same, so the data from the database gonna push it into the favorites menu.
but, it couldn't show in the favorites menu, and when I checked on the console, it said that
[ng:areq] Argument 'fn' is not a function, got string
Did I make something wrong on here? Or maybe I put a wrong method on here?
Thank you in advance.
The error you present seems to be a syntax problem. You are missing the array brackets.
.filter('favoriteFilter', ['$localStorage', function (localStorage) {
if(localStorage.getItem('favorites')!=undefined)
{
var out = [];
return out;
}
else
{
return function (dishes) {
var old_favorite = JSON.parse($localStorage.get('favorites'));
var leng = Object.keys(old_favorite).length;
console.log(leng);
var out = [];
for (var i = 0; i < leng; i++) {
for (var j = 0; j < dishes.length; j++) {
if (dishes[j].id === favorites[i].id)
out.push(dishes[j]);
}
}
return out;
}
};
}]);
I didn't check your logic function, this will be the answer to solve your error.
Try a different approach:
As you already have addToFavorites and deleteFromFavorites functions, all you have to do is simply follow these 3 steps:
When defining you 'favorites' array, simply assign it as follows:
var favorites = JSON.parse(window.localStorage['favorites'] || []);
In your addToFavorites function, after you push the added item to your array, add: window.localStorage['favorites'] = JSON.stringify(favorites);
In your deleteFromFavorites function, after you splice your array, add: window.localStorage['favorites'] = JSON.stringify(favorites);
You should be good to go with these three super simple steps!

AngularJs pagination on grouping elements

I'm trying to paginate over a grouped list, but I have the error of circular dependencies.
I'm new about angular, got this code from other answer on SO here, but cannot paginate it.
This is a fiddle: http://jsfiddle.net/Tropicalista/qyb6N/1/
angular.module('test', ['ui.bootstrap']);
function Main($scope, $q) {
$scope.players = [//my data]
// create a deferred object to be resolved later
var teamsDeferred = $q.defer();
// return a promise. The promise says, "I promise that I'll give you your
// data as soon as I have it (which is when I am resolved)".
$scope.teams = teamsDeferred.promise;
// create a list of unique teams
var uniqueTeams = unique($scope.players, 'team');
// resolve the deferred object with the unique teams
// this will trigger an update on the view
teamsDeferred.resolve(uniqueTeams);
// function that takes an array of objects
// and returns an array of unique valued in the object
// array for a given key.
// this really belongs in a service, not the global window scope
function unique(data, key) {
var result = [];
for (var i = 0; i < data.length; i++) {
var value = data[i][key];
if (result.indexOf(value) == -1) {
result.push(value);
}
}
$scope.noOfPages = Math.ceil(result.length / 10);
return result;
}
$scope.currentPage = 1;
$scope.pageSize = 5;
$scope.maxSize = 2;
}
angular.filter('startFrom', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
Fixed the code for you. http://jsfiddle.net/93Rd3/
You need to change the order when applying the filters.
<div ng-repeat="team in teams| startFrom:(currentPage - 1)*pageSize | limitTo:pageSize ">
And you'd better check the text passing into the filter if it is undefined:
app.filter('startFrom', function () {
return function (input, start) {
if (input === undefined || input === null || input.length === 0) return [];
start = +start; //parse to int
return input.slice(start);
}
});

Resources