Le script ci-dessous affiche un panier d’ ng-repeat
utilisant ng-repeat
. Pour chaque élément du tableau, il affiche le nom de l’élément, son montant et le sous-total ( product.price * product.quantity
).
Quelle est la manière la plus simple de calculer le prix total des éléments répétés?
Product Quantity Price {{product.name}} {{product.quantity}} {{product.price * product.quantity}} € Total :
En gabarit
Total: {{ getTotal() }}
En contrôleur
$scope.getTotal = function(){ var total = 0; for(var i = 0; i < $scope.cart.products.length; i++){ var product = $scope.cart.products[i]; total += (product.price * product.quantity); } return total; }
Cela fonctionne également à la fois le filtre et la liste normale. La première chose à créer un nouveau filtre pour la sum de toutes les valeurs de la liste, et également une solution pour une sum de la quantité totale. Dans le code détaillé, vérifiez le lien du violon .
angular.module("sampleApp", []) .filter('sumOfValue', function () { return function (data, key) { if (angular.isUndefined(data) || angular.isUndefined(key)) return 0; var sum = 0; angular.forEach(data,function(value){ sum = sum + parseInt(value[key], 10); }); return sum; } }).filter('totalSumPriceQty', function () { return function (data, key1, key2) { if (angular.isUndefined(data) || angular.isUndefined(key1) || angular.isUndefined(key2)) return 0; var sum = 0; angular.forEach(data,function(value){ sum = sum + (parseInt(value[key1], 10) * parseInt(value[key2], 10)); }); return sum; } }).controller("sampleController", function ($scope) { $scope.items = [ {"id": 1,"details": "test11","quantity": 2,"price": 100}, {"id": 2,"details": "test12","quantity": 5,"price": 120}, {"id": 3,"details": "test3","quantity": 6,"price": 170}, {"id": 4,"details": "test4","quantity": 8,"price": 70} ]; });
vérifier ce lien de violon
Réalisant cette réponse il y a longtemps, mais je voulais afficher une approche différente non présentée …
Utilisez ng-init
pour calculer votre total. De cette façon, vous n’avez pas à parcourir le HTML et à parcourir le contrôleur. Dans ce scénario, je pense que c’est une solution plus propre / plus simple. (Si la logique de calcul était plus complexe, je recommanderais certainement de déplacer la logique vers le contrôleur ou le service, selon le cas.)
Product Quantity Price {{product.name}} {{product.quantity}} {{itemTotal}} € Total : {{ controller.Total }} // Here is the total value of my cart
Bien entendu, dans votre contrôleur, définissez / initialisez simplement votre champ Total
:
// random controller snippet function yourController($scope..., blah) { var vm = this; vm.Total = 0; }
Vous pouvez calculer le total à l’intérieur de ng-repeat
:
{{ product.name }} {{ product.quantity }} ${{ product.price * product.quantity }} Total ${{ total }}
Vérifiez le résultat ici: http://plnkr.co/edit/Gb8XiCf2RWiozFI3xWzp?p=preview
En cas de résultat de la mise à jour automatique: http://plnkr.co/edit/QSxYbgjDjkuSH2s5JBPf?p=preview (Merci – VicJordan)
filtre personnalisé doux et simple:
(mais lié uniquement à la sum simple des valeurs, pas au produit de sum, j’ai créé le filtre sumProduct
et l’a ajouté comme édition à ce post).
angular.module('myApp', []) .filter('total', function () { return function (input, property) { var i = input instanceof Array ? input.length : 0; // if property is not defined, returns length of array // if array has zero length or if it is not an array, return zero if (typeof property === 'undefined' || i === 0) { return i; // test if property is number so it can be counted } else if (isNaN(input[0][property])) { throw 'filter total can count only numeric values'; // finaly, do the counting and return total } else { var total = 0; while (i--) total += input[i][property]; return total; } }; })
C’est le filtre sumProduct
, il accepte un nombre quelconque d’arguments. En tant qu’argument, il accepte le nom de la propriété à partir des données d’entrée et il peut gérer les propriétés nestedes (imbrication marquée par point: property.nested
);
voici JS Fiddle et le code
angular.module('myApp', []) .filter('sumProduct', function() { return function (input) { var i = input instanceof Array ? input.length : 0; var a = arguments.length; if (a === 1 || i === 0) return i; var keys = []; while (a-- > 1) { var key = arguments[a].split('.'); var property = getNestedPropertyByKey(input[0], key); if (isNaN(property)) throw 'filter sumProduct can count only numeric values'; keys.push(key); } var total = 0; while (i--) { var product = 1; for (var k = 0; k < keys.length; k++) product *= getNestedPropertyByKey(input[i], keys[k]); total += product; } return total; function getNestedPropertyByKey(data, key) { for (var j = 0; j < key.length; j++) data = data[key[j]]; return data; } } })
Solution simple
Voici une solution simple. Pas de boucle supplémentaire requirejse.
Partie HTML
Product Quantity Price {{product.name}} {{product.quantity}} {{product.price * product.quantity}} € Total : {{cart.TotalAmt}} // Here is the total value of my cart
Partie script
$scope.cart.TotalAmt = 0; $scope.CalculateSum= function (product) { $scope.cart.TotalAmt += (product.price * product.quantity); } //It is enough to Write code $scope.cart.TotalAmt =0; in the function where the cart.products get allocated value. $scope.ResetTotalAmt = function (product) { $scope.cart.TotalAmt =0; }
Une autre manière de résoudre ce problème, allant de la réponse de Vaclav à la résolution de ce calcul particulier, à savoir un calcul sur chaque ligne.
.filter('total', function () { return function (input, property) { var i = input instanceof Array ? input.length : 0; if (typeof property === 'undefined' || i === 0) { return i; } else if (typeof property === 'function') { var total = 0; while (i--) total += property(input[i]); return total; } else if (isNaN(input[0][property])) { throw 'filter total can count only numeric values'; } else { var total = 0; while (i--) total += input[i][property]; return total; } }; })
Pour ce faire avec un calcul, ajoutez simplement une fonction de calcul à votre scope, par exemple
$scope.calcItemTotal = function(v) { return v.price*v.quantity; };
Vous utiliseriez {{ datas|total:calcItemTotal|currency }}
dans votre code HTML. Cela présente l’avantage de ne pas être appelé pour chaque résumé, car il utilise des filtres et peut être utilisé pour des totaux simples ou complexes.
JSFiddle
C’est un moyen simple de le faire avec ng-repeat et ng-init pour agréger toutes les valeurs et étendre le modèle avec une propriété item.total.
{{item.name}} {{item.quantity}} {{item.unitCost | number:2}} {{item.total | number:2}} Totals {{invoiceCount}} {{invoiceTotal | number:2}}
La directive ngInit appelle la fonction totale définie pour chaque élément. La fonction setTotals du contrôleur calcule le total de chaque élément. Il utilise également les variables de scope invoiceCount et invoiceTotal pour agréger (sum) la quantité et le total de tous les éléments.
$scope.setTotals = function(item){ if (item){ item.total = item.quantity * item.unitCost; $scope.invoiceCount += item.quantity; $scope.invoiceTotal += item.total; } }
pour plus d’informations et de démonstration, regardez ce lien:
http://www.ozkary.com/2015/06/angularjs-calculate-totals-using.html
Je préfère des solutions élégantes
En gabarit
Total: {{ totalSum }}
En contrôleur
$scope.totalSum = Object.keys(cart.products).map(function(k){ return +cart.products[k].price; }).reduce(function(a,b){ return a + b },0);
Si vous utilisez ES2015 (alias ES6)
$scope.totalSum = Object.keys(cart.products).map(function(k){ return +cart.products[k].price; }).reduce((a,b) => a + b);
J’ai développé un peu la réponse de RajaShilpa. Vous pouvez utiliser la syntaxe comme:
{{object | sumOfTwoValues:'quantity':'products.productWeight'}}
afin que vous puissiez accéder à l’object enfant d’un object. Voici le code du filtre:
.filter('sumOfTwoValues', function () { return function (data, key1, key2) { if (typeof (data) === 'undefined' || typeof (key1) === 'undefined' || typeof (key2) === 'undefined') { return 0; } var keyObjects1 = key1.split('.'); var keyObjects2 = key2.split('.'); var sum = 0; for (i = 0; i < data.length; i++) { var value1 = data[i]; var value2 = data[i]; for (j = 0; j < keyObjects1.length; j++) { value1 = value1[keyObjects1[j]]; } for (k = 0; k < keyObjects2.length; k++) { value2 = value2[keyObjects2[k]]; } sum = sum + (value1 * value2); } return sum; } });
Prendre la réponse de Vaclav et la rendre plus angular:
angular.module('myApp').filter('total', ['$parse', function ($parse) { return function (input, property) { var i = input instanceof Array ? input.length : 0, p = $parse(property); if (typeof property === 'undefined' || i === 0) { return i; } else if (isNaN(p(input[0]))) { throw 'filter total can count only numeric values'; } else { var total = 0; while (i--) total += p(input[i]); return total; } }; }]);
Cela vous donne l’avantage de même accéder aux données nestedes et aux tableaux:
{{data | total:'values[0].value'}}
En html
Total Amount: ${{ data.allTicketsTotalPrice() }}
en javascript
app.controller('myController', function ($http) { var vm = this; vm.allTicketsTotalPrice = function () { var totalPrice = 0; angular.forEach(vm.ticketTotalPrice, function (value, key) { totalPrice += parseFloat(value); }); return totalPrice.toFixed(2); }; });
La réponse de Huy Nguyen est presque là. Pour que cela fonctionne, ajoutez:
ng-repeat="_ in [ products ]"
… à la ligne avec ng-init. La liste contient toujours un seul élément, donc Angular répète le bloc exactement une fois.
La démo de Zybnek utilisant le filtrage peut être réalisée en ajoutant:
ng-repeat="_ in [ [ products, search ] ]"
voici ma solution à ce problème:
Total: {{ calculateTotal() }}
scénario
$scope.calculateVAT = function () { $scope.cart.products.reduce((accumulator, currentValue) => accumulator + (currentValue.price * currentValue.quantity), 0); };
réduire s’exécutera pour chaque produit dans la masortingce de produits. Accumulator est la quantité totale accumulée, currentValue est l’élément actuel du tableau et le 0 dans la dernière est la valeur initiale
Après avoir lu toutes les réponses ici – comment résumer les informations groupées, j’ai décidé de tout ignorer et juste de charger une des bibliothèques javascript SQL. J’utilise alasql, oui, cela prend quelques secondes de plus sur le temps de chargement mais économise un temps incalculable de codage et de débogage, maintenant pour regrouper et additionner ()
$scope.bySchool = alasql('SELECT School, SUM(Cost) AS Cost from ? GROUP BY School',[restResults]);
Je sais que cela peut sembler un peu désagréable pour les angles / js, mais en réalité, SQL a résolu ce problème il y a plus de 30 ans et nous ne devrions pas avoir à le réinventer dans un navigateur.