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

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

Related

Infdig in Custom groupBy

i recently needed some kinda customized repeater, which group data by their key, but not simply group them all together, so i read several references and things,... and at last i come up to copy
groupBy from this article which he seem to complete it at best, ...
http://sobrepere.com/blog/2014/10/14/creating-groupby-filter-angularjs/
And then i customized so it become like this:
the things my group by do... is:
Group Data Together Until It Reach Differences.
but the matter is that though it work, it still generate infdig, i know it's because the digest done call other one, but what i don't know is how to solve it in very easy and understandable manner, as i'm new to JavaScript...
app.filter('groupBy', function () {
var results = {};
return function (data, key) { //Data => My Objects Array - Key => Name Of Filtered Property
if (!(data && key)) return;
var result;
if (!this.$id) {
result = {};
} else {
var scopeId = this.$id;
if (!results[scopeId]) {
results[scopeId] = {};
this.$on("$destroy", function () {
delete results[scopeId];
});
}
result = results[scopeId];
}
for (var groupKey in result)
result[groupKey].splice(0, result[groupKey].length);
var grpKey = -1; //GroupKey
var lastUserId;
for (var i = 0; i < data.length; i++) {
if (!result[grpKey] || lastUserId && lastUserId != data[i][key]) // Ex.: result[data[0]["UserId"]]{ => return UserId
result[++ grpKey] = [];
result[grpKey].push(data[i]);
lastUserId = data[i][key];
}
var keys = Object.keys(result);
for (var k = 0; k < keys.length; k++) {
if (result[keys[k]].length === 0)
delete result[keys[k]];
}
return result;
};
});
In this url is working perfectly...
http://plnkr.co/edit/8jB4wSRtKfVmEsTGZtfV?p=preview
app.filter('groupBy', function ($timeout) {
return function (data, key) {
if (!key) return data;
var outputPropertyName = '__groupBy__' + key;
if(!data[outputPropertyName]){
var result = {};
for (var i=0;i<data.length;i++) {
if (!result[data[i][key]])
result[data[i][key]]=[];
result[data[i][key]].push(data[i]);
}
Object.defineProperty(result, 'length', {enumerable: false, value: Object.keys(result).length});
Object.defineProperty(data, outputPropertyName, {enumerable:false, configurable:true, writable: false, value:result});
$timeout(function(){delete data[outputPropertyName];},0,false);
}
return data[outputPropertyName];
};
});

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!

In AngularJs set a variable in forEach for each object

I am trying to run a forEach function with data from a query and I want to set a variable for each object in that data to be able to use in a ng-repeat. I keep overriding the variable and cannot wrap my head around setting the variable for each one.
CategoryCardService.query({}, function (data) {
$scope.categoryCards = data;
angular.forEach(data, function (value) {
var categoryOccupancyPercent = $filter('number')(value.occupancy_percent * 100, 0);
var categoryTotalTurnover = value.total_turnover;
var doughnut_chart_min = 0;
var doughnut_chart_max = 0;
doughnut_chart_min = categoryOccupancyPercent;
doughnut_chart_max = 100 - categoryOccupancyPercent;
data.doughnutData = [doughnut_chart_min, doughnut_chart_max];
data.display = categoryOccupancyPercent + '%';
});
});
Pass in the key and assign like that.
CategoryCardService.query({}, function (data) {
$scope.categoryCards = data;
angular.forEach(data, function (value, key) {
// ...
data[key].display = categoryOccupancyPercent + '%';
});
});

$compile within $compile not getting applied

I have a directive which takes in an array of container objects and $compiles a new container directive for each container and each nested container. It also compiles a resize handle before all containers except the first child. The link function looks like this:
//scope.dock is retrieved from a factory
scope.initContainers = function () {
var prevScope;
for (var i = 0; i < scope.dock.containers.length; i++) {
var newScope = scope.$new(true);
newScope.container = scope.dock.containers[i];
var newElement = '<panel-container class=\"' + scope.dock.containers[i].axis + '" ></panel-container>';
var newTemplate = $compile(newElement)(newScope);
if (i > 0) {
var sizerScope = scope.$new(true);
sizerScope.containerOne = prevScope;
sizerScope.containerTwo = newScope;
var sizerElement = '<resize-handle class=\"' + scope.dock.containers[i].axis + '"></resize-handle>';
var sizerTemplate = $compile(sizerElement)(sizerScope);
element.append(sizerTemplate);
}
element.append(newTemplate);
if (scope.dock.containers[i].containers.length > 0) {
generateContainers(scope.dock.containers[i], newScope, newTemplate);
}
}
return scope;
};
scope.sizeContainers = function () {
scope.$broadcast('size-containers');
};
var generateContainers = function (value, parentScope, parentElement) {
var prevScope;
for (var y = 0; y < value.containers.length; y++) {
var newChildScope = parentScope.$new(true);
newChildScope.container = value.containers[y];
var newChildElement = '<panel-container class=\"' + value.containers[y].axis + '" ></panel-container>';
var newChildTemplate = $compile(newChildElement)(newChildScope);
if (y > 0) {
var sizerScope = parentScope.$new(true);
sizerScope.containerOne = prevScope;
sizerScope.containerTwo = newChildScope;
var sizerElement = '<resize-handle class=\"' + value.containers[y].axis + '"></resize-handle>';
var sizerTemplate = $compile(sizerElement)(sizerScope);
parentElement.append(sizerTemplate);
}
parentElement.append(newChildTemplate);
if(typeof value.containers[y].containers !== 'undefined') {
if (value.containers[y].containers.length > 0) {
generateContainers(value.containers[y], newChildScope, newChildTemplate);
}
}
prevScope = newChildScope;
}
};
scope.initContainers().sizeContainers();
My problem is that the first child layer compiles but the second one does not. It does, however, work when I add scope.$apply to the end of generateContainers. Unfortunately for some reason it is skipping the first child element for each container and throwing a 'digest in progress' error.
Does anyone have any ideas on how to get this to compile?
And could someone explain why scope.$apply() is compiling the second layer only after I explicitly call it, even when $digest is already running?
I fixed this by getting rid of initContainers (since it was exactly the same as generateContainers) and moving that function to the container directive as well. That way the root directive wasn't trying to compile everything.

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