Reputation: 8663
I have a JSON file with some data, for example:
$scope.expenses = [
{
"amount": "100",
"SpentOn": "19/04/2014",
"IsExpensable": true,
},
{
"amount": "200",
"SpentOn": "20/04/2014",
"IsExpensable": true,
},
{
"amount": "50",
"SpentOn": "01/01/2014",
"IsExpensable": true,
},
{
"amount": "350",
"SpentOn": "01/09/2013",
"IsExpensable": false,
}
];
I am trying to write an angular function that loops through the above, when IsExpensable= true, an then performs a count on the mm and yyyy to determine how many expenses were made that month. So in the example above, in April 2014, there were 2. In Jan 2010, there was 1.
Heres my JS:
$scope.MyDateFilterFunction = function () {
var data = [];
var dataMonth = [];
var dataYear = [];
var Jan = 0;
var Feb = 0;
var Mar = 0;
var Apr = 0;
var May = 0;
var May = 0;
var Jun = 0;
var Jul = 0;
var Aug = 0;
var Sep = 0;
var Oct = 0;
var Nov = 0;
var Dec = 0;
angular.forEach($scope.expenses, function (value, key) {
if (value.IsExpensable) {
angular.forEach($scope.expenses, function (value, key) {
data = value.SpentOn.split('/');
dataMonth = data[1];
dataYear = data[2];
var count = (dataMonth.split("04").length - 1)
console.log("April occurances" + count.length);
// Add count to var Apr
});
}
});
return data;
};
My HTML:
<td ng-repeat="exp in MyDateFilterFunction ()">
{[{exp}]}
</td>
UPDATE:
Have added:
if (dataMonth == "04") {
Apr = Apr + 1;
console.log(Apr);
}
However the console output is: 1 2 3 4 1 2 3 4 1 2 3 4
Resolved by removing second angular.forEach
statement
Upvotes: 0
Views: 93
Reputation: 48212
From Mike's (underscore-based) answer:
"Just imagine writing a solution to this in your own code" - Challenge accepted !
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
$scope.groupped = $scope.expenses
/* Only give me expensable items */
.filter(function (exp) {
return exp.IsExpensable;
})
/* Determine each item's group (with friendly display name) */
.map(function (exp) {
var dateArr = exp.SpentOn.split('/');
var groupValue = '' + months[parseInt(dateArr[1]) - 1] +
' ' + dateArr[2];
return groupValue;
})
/* Map group-names to items-count */
.reduce(function (groupped, groupValue) {
groupped[groupValue] = (groupped[groupValue] || 0) + 1;
return groupped;
}, {});
<div ng-repeat="(time, count) in groupped">
{{time}}: {{count}}
</div>
If (for whatever reason) you prefer to have an array instead of an object:
$scope.groupped = ...;
$scope.grouppedArr = Object.keys($scope.groupped).map(function (key) {
return {name: key, count: $scope.groupped[key]};
});
<div ng-repeat="group in grouppedArr">
{{group.name}}: {{group.count}}
</div>
See, also, this short demo
Note 1:
In both cases (vanilla JS, underscore) extra logic is required in order to sort the results by month index.
Note 2:
If you plan to support older versions of browsers (yeah, I mean like IE < 9), you might want to use a library like underscore or lodash for their fallbacks.
Upvotes: 3
Reputation: 2882
I know that you're skeptical about using Underscore, but I think it's almost essential for any application. Consider the answer to your question below while using the library:
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
$scope.data = _.chain($scope.expenses)
// Only give me expensable items
.filter(function(exp) {
return exp.IsExpensable;
})
// group them by the month and year (with friendly display string)
.groupBy(function(exp) {
var dateAr = exp.SpentOn.split('/');
var groupValue = '' + months[parseInt(dateAr[1])] + ' ' + dateAr[2];
return groupValue;
})
// Map to a list of objects with time (friendly display string) and number of transactions
.map(function(group, key) {
return {
time: key,
transactions: group.length
};
})
// End the chain
.value();
Then in your html:
<div ng-repeat="item in data">
{{item.time}}: {{item.transactions}}
</div>
It's really unbelievable how much underscore can help make your life easier. I guarantee you'll use it in far more than one place in your application. It's also extremely lightweight (5kB minified and gzipped). Just imagine writing a solution to this in your own code while making it portable to other parts of your application.
Upvotes: 2