Menghitung jumlah elemen berulang di AngularJS ng-repeat


107

Script di bawah ini menampilkan gerobak toko menggunakan ng-repeat. Untuk setiap elemen dalam larik, ini menunjukkan nama item, jumlahnya, dan subtotal ( product.price * product.quantity).

Apa cara paling sederhana untuk menghitung harga total elemen berulang?

<table>

    <tr>
        <th>Product</th>
        <th>Quantity</th>
        <th>Price</th>
    </tr>

    <tr ng-repeat="product in cart.products">
        <td>{{product.name}}</td>
        <td>{{product.quantity}}</td>
        <td>{{product.price * product.quantity}} €</td>
    </tr>

    <tr>
        <td></td>
        <td>Total :</td>
        <td></td> <!-- Here is the total value of my cart -->
    </tr>

</table>

1
angular.forEach ($ scope.cart.products, function (filterObj, filterKey) {$ scope.total + = filterObj.product.price * filterObj.product.quantity;});
Gery



Mengapa Anda tidak menggunakan tfoot-tag?
Pascal

Jawaban:


147

Di Template

<td>Total: {{ getTotal() }}</td>

Di Controller

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

24
satu kelemahan dari ini adalah bahwa itu mengulang koleksi dua kali. ini bagus untuk koleksi kecil, tetapi bagaimana jika koleksinya agak besar? Sepertinya dalam ng-repeat harus ada cara untuk menjalankan penjumlahan pada bidang objek tertentu.
icfantv

2
@Pascamel Periksa jawaban saya ( stackoverflow.com/questions/22731145/… ) saya pikir yang itu bekerja untuk apa yang Anda tanyakan dengan filter
Rajamohan Anguchamy

persis seperti yang saya cari ketika saya mendapatkan pertanyaan itu, terima kasih atas perhatiannya @RajaShilpa!
Pascamel

2
Masalah utama dengan solusi ini adalah totalnya akan dihitung ulang dengan setiap intisari, karena ini adalah panggilan fungsi.
Marc Durdin

@icfantv bagaimana iterasi atas koleksi dua kali?
Crhistian Ramirez

58

Ini juga berfungsi pada filter dan daftar normal. Hal pertama untuk membuat filter baru untuk jumlah semua nilai dari daftar, dan juga memberikan solusi untuk jumlah total kuantitas. Dalam kode detail periksa tautan fiddler .

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


<div ng-app="sampleApp">
  <div ng-controller="sampleController">
    <div class="col-md-12 col-lg-12 col-sm-12 col-xsml-12">
      <label>Search</label>
      <input type="text" class="form-control" ng-model="searchFilter" />
    </div>
    <div class="col-md-12 col-lg-12 col-sm-12 col-xsml-12">
      <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2">
        <h4>Id</h4>

      </div>
      <div class="col-md-4 col-lg-4 col-sm-4 col-xsml-4">
        <h4>Details</h4>

      </div>
      <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">
        <h4>Quantity</h4>

      </div>
      <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">
        <h4>Price</h4>

      </div>
      <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">
        <h4>Total</h4>

      </div>
      <div ng-repeat="item in resultValue=(items | filter:{'details':searchFilter})">
        <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2">{{item.id}}</div>
        <div class="col-md-4 col-lg-4 col-sm-4 col-xsml-4">{{item.details}}</div>
        <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">{{item.quantity}}</div>
        <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">{{item.price}}</div>
        <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">{{item.quantity * item.price}}</div>
      </div>
      <div colspan='3' class="col-md-8 col-lg-8 col-sm-8 col-xsml-8 text-right">
        <h4>{{resultValue | sumOfValue:'quantity'}}</h4>

      </div>
      <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">
        <h4>{{resultValue | sumOfValue:'price'}}</h4>

      </div>
      <div class="col-md-2 col-lg-2 col-sm-2 col-xsml-2 text-right">
        <h4>{{resultValue | totalSumPriceQty:'quantity':'price'}}</h4>

      </div>
    </div>
  </div>
</div>

periksa Tautan Biola ini


Hei saya mendapatkan 'undefined'saat menggunakan resultValue, tetapi jika saya menggunakannya itemsberfungsi dengan baik, ada ide .. ??
Salal Aslam

Di mana pertama Anda memeriksa kode berikut "resultValue = (items | filter: {'details': searchFilter})", karena semua nilai filter disimpan dalam variabel "resultValue" itu. saya pikir Anda salah untuk itu {} atau () ini, verifikasi sekali lagi.
Rajamohan Anguchamy

Jika saya menggunakannya itemstidak akan berfungsi dengan filter, tolong!
Salal Aslam

kode saya adalah seperti ini ng-repeat="campaign in filteredCampaigns=(campaigns | filter:{'name':q})"dan{{ filteredCampaigns | campaignTotal: 'totalCommission' | number: 2 }}
Salal Aslam

ya, karena item belum tersaring, maka setelah filter terjadi hasil tersebut harus disimpan ke model lain dan sebaiknya hanya menggunakan model tersebut saja. Dalam sampel saya, saya menggunakan model "resultValue".
Rajamohan Anguchamy

41

Menyadari ini menjawab lama, tetapi ingin memposting pendekatan yang berbeda tidak disajikan ...

Gunakan ng-inituntuk menghitung total Anda. Dengan cara ini, Anda tidak perlu mengulang di HTML dan melakukan iterasi di pengontrol. Dalam skenario ini, saya pikir ini adalah solusi yang lebih bersih / sederhana. (Jika logika penghitungan lebih kompleks, saya pasti akan merekomendasikan untuk memindahkan logika ke pengontrol atau layanan yang sesuai.)

    <tr>
        <th>Product</th>
        <th>Quantity</th>
        <th>Price</th>
    </tr>

    <tr ng-repeat="product in cart.products">
        <td>{{product.name}}</td>
        <td>{{product.quantity}}</td>
        <td ng-init="itemTotal = product.price * product.quantity; controller.Total = controller.Total + itemTotal">{{itemTotal}} €</td>
    </tr>

    <tr>
        <td></td>
        <td>Total :</td>
        <td>{{ controller.Total }}</td> // Here is the total value of my cart
    </tr>

Tentu saja, di pengontrol Anda, cukup tentukan / inisialisasi Totalbidang Anda :

// random controller snippet
function yourController($scope..., blah) {
    var vm = this;
    vm.Total = 0;
}

4
Ini jelas merupakan cara yang paling bersudut. Sederhana, mudah dibaca, dan deklaratif. Jadi, logika yang diwakilinya tetap di tempatnya.
Daniel Leiszen

Metode ini menyembunyikan kalkulasi dalam presentasi sel, yang mudah dipahami di sini, tetapi menjadi sangat berantakan dengan tabel yang rumit.
Marc Durdin

1
Masalah lain dengan ini adalah tidak ada ikatan dua arah juga.
Paul Carlton

17

Anda dapat menghitung total dalam ng-repeatmengikuti:

<tbody ng-init="total = 0">
  <tr ng-repeat="product in products">
    <td>{{ product.name }}</td>
    <td>{{ product.quantity }}</td>
    <td ng-init="$parent.total = $parent.total + (product.price * product.quantity)">${{ product.price * product.quantity }}</td>
  </tr>
  <tr>
    <td>Total</td>
    <td></td>
    <td>${{ total }}</td>
  </tr>
</tbody>

Periksa hasilnya di sini: http://plnkr.co/edit/Gb8XiCf2RWiozFI3xWzp?p=preview

Dalam kasus hasil pembaruan otomatis: http://plnkr.co/edit/QSxYbgjDjkuSH2s5JBPf?p=preview (Terima kasih - VicJordan)


ini tidak akan berfungsi ketika daftar difilter - tbodydiinisialisasi hanya sekali, tetapi trsetiap kali daftar difilter, mengakibatkan jumlah yang salah
Zbynek

Bisakah Anda membuat contoh di plnkr atau jsfiddle?
Huy Nguyen

Hmm, ya, ini tidak berfungsi di filter karena filter di sini hanya menampilkan / menyembunyikan tampilan, bukan memperbarui$scope
Huy Nguyen

@HuyNguyen, saya telah mengedit kode Anda di atas. Silakan periksa di sini: plnkr.co/edit/QSxYbgjDjkuSH2s5JBPf?p=preview . Di sini yang saya inginkan adalah jika pengguna mengubah kuantitas maka kolom ke-4 (harga * kuantitas) harus diperbarui secara otomatis. Bisakah Anda memeriksanya. Terima kasih
Vikasdeep Singh

9

Ini solusi saya

filter khusus yang manis dan sederhana:

(tetapi hanya terkait dengan jumlah nilai sederhana, bukan jumlah produk, saya telah membuat sumProductfilter dan menambahkannya sebagai edit pada posting ini).

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

JS Fiddle

EDIT: sumProduct

Ini adalah sumProductfilter, ini menerima sejumlah argumen. Sebagai argumen, ia menerima nama properti dari data masukan, dan dapat menangani properti bersarang (bersarang ditandai dengan titik :) property.nested;

  • Meneruskan argumen nol mengembalikan panjang data input.
  • Meneruskan hanya satu argumen akan mengembalikan jumlah nilai sederhana dari properti itu.
  • Meneruskan lebih banyak argumen akan menghasilkan jumlah produk dari nilai properti yang diteruskan (jumlah skalar properti).

inilah JS Fiddle dan kodenya

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

JS Fiddle


4

Solusi Sederhana

Inilah solusi sederhana. Tidak diperlukan loop tambahan.

Bagian HTML

         <table ng-init="ResetTotalAmt()">
                <tr>
                    <th>Product</th>
                    <th>Quantity</th>
                    <th>Price</th>
                </tr>

                <tr ng-repeat="product in cart.products">
                    <td ng-init="CalculateSum(product)">{{product.name}}</td>
                    <td>{{product.quantity}}</td>
                    <td>{{product.price * product.quantity}} €</td>
                </tr>

                <tr>
                    <td></td>
                    <td>Total :</td>
                    <td>{{cart.TotalAmt}}</td> // Here is the total value of my cart
                </tr>

           </table>

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

3

Cara lain untuk menyelesaikan ini, memperluas dari jawaban Vaclav untuk menyelesaikan perhitungan khusus ini - yaitu perhitungan pada setiap baris.

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

Untuk melakukan ini dengan kalkulasi, cukup tambahkan fungsi kalkulasi ke ruang lingkup Anda, mis

$scope.calcItemTotal = function(v) { return v.price*v.quantity; };

Anda akan menggunakannya {{ datas|total:calcItemTotal|currency }}dalam kode HTML Anda. Ini memiliki keuntungan karena tidak dipanggil untuk setiap intisari, karena menggunakan filter, dan dapat digunakan untuk total sederhana atau kompleks.

JSFiddle


3

Ini adalah cara sederhana untuk melakukan ini dengan ng-repeat dan ng-init untuk menggabungkan semua nilai dan memperluas model dengan properti item.total.

<table>
<tr ng-repeat="item in items" ng-init="setTotals(item)">
                    <td>{{item.name}}</td>
                    <td>{{item.quantity}}</td>
                    <td>{{item.unitCost | number:2}}</td>
                    <td>{{item.total | number:2}}</td>
</tr>
<tr class="bg-warning">
                    <td>Totals</td>
                    <td>{{invoiceCount}}</td>
                    <td></td>                    
                    <td>{{invoiceTotal | number:2}}</td>
                </tr>
</table>

Direktif ngInit memanggil fungsi total yang ditetapkan untuk setiap item. Fungsi setTotals di pengontrol menghitung setiap total item. Ini juga menggunakan variabel lingkup invoiceCount dan invoiceTotal untuk menggabungkan (jumlah) kuantitas dan total untuk semua item.

$scope.setTotals = function(item){
        if (item){
            item.total = item.quantity * item.unitCost;
            $scope.invoiceCount += item.quantity;
            $scope.invoiceTotal += item.total;
        }
    }

untuk informasi lebih lanjut dan demo lihat tautan ini:

http://www.ozkary.com/2015/06/angularjs-calculate-totals-using.html


1
Tautan ke entri blog Anda yang mungkin menjadi tautan mati tidak disarankan di StackOverlow. Juga, ketika saya melihat halaman tersebut, saya mendapatkan error 502 Bad Gateway di tengah halaman Anda. Jawab pertanyaan di sini bukan tautan ke tempat lain.
Rick Glos

3

Saya lebih suka solusi elegan

Di Template

<td>Total: {{ totalSum }}</td>

Di Controller

$scope.totalSum = Object.keys(cart.products).map(function(k){
    return +cart.products[k].price;
}).reduce(function(a,b){ return a + b },0);

Jika Anda menggunakan ES2015 (alias ES6)

$scope.totalSum = Object.keys(cart.products)
  .map(k => +cart.products[k].price)
  .reduce((a, b) => a + b);

2

Anda bisa menggunakan filter Angular kustom yang mengambil array objek set data dan kunci di setiap objek untuk dijumlahkan. Filter kemudian dapat mengembalikan jumlah:

.filter('sumColumn', function(){
        return function(dataSet, columnToSum){
            let sum = 0;

            for(let i = 0; i < dataSet.length; i++){
                sum += parseFloat(dataSet[i][columnToSum]) || 0;
            }

            return sum;
        };
    })

Kemudian di tabel Anda untuk menjumlahkan kolom, Anda dapat menggunakan:

<th>{{ dataSet | sumColumn: 'keyInObjectToSum' }}</th>

1

Anda dapat mencoba menggunakan layanan angular js, ini berhasil untuk saya..memberikan cuplikan kode di bawah ini

Kode pengontrol:

$scope.total = 0;
var aCart = new CartService();

$scope.addItemToCart = function (product) {
    aCart.addCartTotal(product.Price);
};

$scope.showCart = function () {    
    $scope.total = aCart.getCartTotal();
};

Kode Layanan:

app.service("CartService", function () {

    Total = [];
    Total.length = 0;

    return function () {

        this.addCartTotal = function (inTotal) {
            Total.push( inTotal);
        }

        this.getCartTotal = function () {
            var sum = 0;
            for (var i = 0; i < Total.length; i++) {
                sum += parseInt(Total[i], 10); 
            }
            return sum;
        }
    };
});

1

inilah solusi saya untuk masalah ini:

<td>Total: {{ calculateTotal() }}</td>

naskah

$scope.calculateVAT = function () {
    return $scope.cart.products.reduce((accumulator, currentValue) => accumulator + (currentValue.price * currentValue.quantity), 0);
};

mengurangi akan mengeksekusi untuk setiap produk dalam larik produk. Akumulator adalah jumlah total yang terakumulasi, currentValue adalah elemen array saat ini dan 0 di terakhir adalah nilai awal


0

Saya memperluas sedikit jawaban RajaShilpa. Anda dapat menggunakan sintaks seperti:

{{object | sumOfTwoValues:'quantity':'products.productWeight'}}

sehingga Anda bisa mengakses objek anak suatu objek. Berikut kode untuk filter tersebut:

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

0

Mengambil jawaban Vaclav dan membuatnya lebih seperti 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;
        }
    };
}]);

Ini memberi Anda keuntungan bahkan dengan mengakses data bersarang dan array:

{{data | total:'values[0].value'}}

0

Dalam html

<b class="text-primary">Total Amount: ${{ data.allTicketsTotalPrice() }}</b>

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

0

Jawaban Huy Nguyen hampir sampai. Untuk membuatnya berhasil, tambahkan:

ng-repeat="_ in [ products ]"

... ke baris ng-init. Daftar selalu memiliki satu item, jadi Angular akan mengulangi blok tersebut tepat satu kali.

Demo Zybnek menggunakan pemfilteran dapat berfungsi dengan menambahkan:

ng-repeat="_ in [ [ products, search ] ]"

Lihat http://plnkr.co/edit/dLSntiy8EyahZ0upDpgy?p=preview .


0
**Angular 6: Grand Total**       
 **<h2 align="center">Usage Details Of {{profile$.firstName}}</h2>
        <table align ="center">
          <tr>
            <th>Call Usage</th>
            <th>Data Usage</th>
            <th>SMS Usage</th>
            <th>Total Bill</th>
          </tr>
          <tr>
          <tr *ngFor="let user of bills$">
            <td>{{ user.callUsage}}</td>
            <td>{{ user.dataUsage }}</td>
            <td>{{ user.smsUsage }}</td>
       <td>{{user.callUsage *2 + user.dataUsage *1 + user.smsUsage *1}}</td>
          </tr>


          <tr>
            <th> </th>
            <th>Grand Total</th>
            <th></th>
            <td>{{total( bills$)}}</td>
          </tr>
        </table>**


    **Controller:**
        total(bills) {
            var total = 0;
            bills.forEach(element => {
total = total + (element.callUsage * 2 + element.dataUsage * 1 + element.smsUsage * 1);
            });
            return total;
        }

Dari Ulasan: Selamat Datang di Stack Overflow! Tolong jangan menjawab hanya dengan kode sumber. Cobalah untuk memberikan gambaran yang bagus tentang bagaimana solusi Anda bekerja. Lihat: Bagaimana cara menulis jawaban yang baik? . Terima kasih
sɐunıɔ ןɐ qɐp

0

Ini solusi saya

<div ng-controller="MainCtrl as mc">
  <ul>
      <li ng-repeat="n in [1,2,3,4]" ng-init="mc.sum = ($first ? 0 : mc.sum) + n">{{n}}</li>
      <li>sum : {{mc.sum}}</li>
  </ul>
</div>

Ini mengharuskan Anda untuk menambahkan nama ke pengontrol Controller as SomeNamesehingga kami dapat menyimpan variabel di sana (apakah benar-benar diperlukan? Saya tidak terbiasa menggunakan $ parent jadi saya tidak tahu)

Kemudian untuk setiap pengulangan, tambahkan ng-init"SomeName.SumVariable = ($first ? 0 : SomeName.SumVariable) + repeatValue"

$first untuk memeriksanya terlebih dahulu kemudian disetel ulang ke nol, jika tidak maka akan melanjutkan nilai agregat

http://jsfiddle.net/thainayu/harcv74f/


-2

Setelah membaca semua jawaban di sini - cara meringkas informasi yang dikelompokkan, saya memutuskan untuk melewatkan semuanya dan hanya memuat salah satu pustaka javascript SQL. Saya menggunakan alasql, ya dibutuhkan beberapa detik lebih lama pada waktu muat tetapi menghemat banyak waktu dalam pengkodean dan debugging, Sekarang untuk mengelompokkan dan menjumlahkan () saya hanya menggunakan,

$scope.bySchool = alasql('SELECT School, SUM(Cost) AS Cost from ? GROUP BY School',[restResults]);

Saya tahu ini terdengar seperti sedikit kata-kata kasar tentang angular / js tetapi benar-benar SQL menyelesaikan ini 30+ tahun yang lalu dan kita tidak perlu menemukannya kembali dalam browser.


1
Ini sangat mengerikan. Wow SMH - Saya akan membiarkan orang lain turun suara. Mulut saya terbuka lebar dengan jawaban ini .....
Tom Stickel
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.