1

All right, here's the setup: I have a table in a "form" whose contents I'm editing using the ContentEditable HTML attribute (set on the parent element of the table). There are four columns all together-- two sets of "item description" columns and two sets of matching "price" columns, along with an area at the bottom where I'd like the for the total price to be displayed.

Problem #1 is that I'm not sure how to calculate the sum of numbers across cells when I'm not working with inputs and fields. Complicating things (at least to me) is that I'm adding rows to the table dynamically with Jquery.

Problem #2 is that the second set of description/price columns are optional-- I'd like to be able to use an "Add" button to trigger individual items in those columns to be added to the total.

Edit: I tried some random things and have had some success by storing the values of the cells in an array, then telling Jquery to add the contents of that array and output the sum. The problem now is that it's not giving me a sum, it's giving me the array contents without whitespace. For example, if the array contains 1,2,3 it gives me 123 instead of 6.

Edit #2: After cobbling together bits and pieces of a half dozen tutorials, I've got something that works for Problem #1. Now on to problem #2!

var sumArray = []
            $('#calc').click(function(){ 
                $('table tbody tr').each(function() {
                    sumArray.push($(this).find('.cost').text().match(/\d+/));                       
                });
                var total = 0;
                for (var i = 0; i < sumArray.length; i++) {
                    total += parseInt(sumArray[i]);
                }
                $('.totalcost').text(total);

            });

Here's the table code:

<table>
            <thead>
                <tr>
                        <th>Service</th>
                        <th>Cost</th>
                        <th>Complementary (Optional) Service</th>
                        <th>Cost</th>

                </tr>
            </thead>
            <tbody>
                <tr>
                    <td></td>
                <td class="cost"></td>
                    <td></td>
                    <td class="compcost"></td>
                </tr>
            </tbody>
            <tfoot>
                <tr>

                        <th>Total</th>
                        <th class="totalcost"></th>

                </tr>
            </tfoot>
        </table>
        <span id="add">Add</span>
        <span id="remove">Remove</span>
        <span id="reset">Reset</span>
        <span id="nocomp">No Comps</span>
        <span id="calc">Calculate Total</span>
    </div>

And here's the JS I'm using right now.

//Add fields to table
            var i = $('tbody>tr').size() + 1;

            $('#add').click(function() {
                if ($("tbody tr:first-child td").length > 2) {
                $('<tr><td></td><td class="cost"></td><td></td><td class="compcost"></td></tr>').fadeIn('slow').appendTo('tbody');
                i++;
                }
                else
                {$('<tr><td></td><td class="cost"></td></tr>').fadeIn('slow').appendTo('tbody');
                i++;
                };

            });

            $('#remove').click(function() {
            if(i > 1) {
                $('tbody>tr:last').remove();
                i--;
            }
            });

            $('#reset').click(function() {
            while(i > 2) {
                $('tbody>tr:last').remove();
                i--;
            }
            });

            $('#nocomp').click(function(){
                if ($("tbody tr td").length > 2) {
                $('thead tr th:nth-child(2),thead tr th:nth-child(3),tbody>tr td:nth-child(2),tbody>tr td:nth-child(3)').remove();
                }
            });

        /*$('#calc').click(function(){
            $('table tbody tr').each(function() {
            $(this).find('.totalcost').text(
            parseFloat($(this).find('.cost').text())
        );
            });
        });*/

        $('#calc').click(function(){ 
            $(this).find('table tbody tr td.cost').each(function(idx)
            {
                var total = $(this).text();
                count += total;                          
            });
            alert(parseInt(count));
        });
ajw-art
  • 173
  • 1
  • 1
  • 12
  • 1
    Why not give all value cells a css class name, then use the jscript to iterate through all cells with that class name, and retrieve the value? – Robert Christ Aug 23 '12 at 17:41
  • @RobertChrist, this would definitely be the way to go around this. Brilliant idea! – Hanlet Escaño Aug 23 '12 at 17:43
  • @RobertChrist currently they do have a class name-- "cost." but for some reason no matter what code I try, I can't get javascript to give me a total value or output it into the cell with the class "totalcost." You can see my attempts to do the calculation in the last two script snippets. – ajw-art Aug 23 '12 at 17:54
  • http://stackoverflow.com/questions/2310145/javascript-getting-value-of-a-td-with-id-name I searched javascript replace value td in google, and found numerous results. If none of those help you, perhaps someone can write you a better answer. – Robert Christ Aug 23 '12 at 18:14
  • Still no dice. I've seen the other tutorials on how to do something similar, but I can't get them to work for me. The most I've been able to do is to get jquery to alert me about the value of each number as it iterates over them, but I can't get it to add them together or to output that sum to the desired position on the page. – ajw-art Aug 23 '12 at 18:59
  • Not sure if this helps, but you can do something very similar to your total cost calculator, and if the user wants to add optional cost have the javascript add an "included" class to the "compcost" cell, then add a couple of lines to your total calculator: `var $this = $(this), includedCompCost = $this.find('.compcost').filter('.included').text().match(/\d+/); sumArray.push($this.find('.cost').text().match(/\d+/)); if (includedCompCost !== "") { sumArray.push(includedCompCost); }` – Laurence Aug 23 '12 at 20:00
  • @Laurence Thanks! I managed something similar by creating an add button that, when clicked, added the class "cost" to the .compost cells, therefore including them in the calculation. Unfortunately this seems to have broken the outputting of the total once more, as it's now giving me a concatenated string again. Not sure why. :/ – ajw-art Aug 23 '12 at 20:25
  • @ajw-art you might have to add a check to the parseInt result since it will return NaN for things that cannot be converted to ints. Try this: `for (var i = 0; i < sumArray.length; i++) { var parsedInt = parseInt(sumArray[i]); if (!isNaN(parsedInt) && parsedInt > 0) { total += parsedInt; } }` – Laurence Aug 23 '12 at 20:35
  • @Laurence Same problem. Additionally, I realize that clicking the "calculate sum" button multiple times causes it to continue to add the sum of the columns to the existing total rather than clearing the total and re-calculating the numbers. Is there a way to prevent this behavior? – ajw-art Aug 23 '12 at 21:15
  • I figured out how to empty the array so that the script does a fresh calculation/total each time. Still having issues with it concatenating though. – ajw-art Aug 23 '12 at 22:06

2 Answers2

1

Take a look at this jsFiddle, it might be what you want: http://jsfiddle.net/mPvyA/3/

I modified your buttons slightly to add/remove an included class then check for that on calculate:

        $('#exccomp').click(function(){
            $('table').find('.compcost').removeClass('included');
        });

        $('#inccomp').click(function(){
            $('table').find('.compcost').addClass('included');
        });

        $('#calc').click(function(){ 
            var sumArray = [];
            $('table tbody tr').each(function() {
                var $this = $(this), 
                    includedCompCost = $this.find('.compcost').filter('.included').text().match(/\d+/);
                sumArray.push($this.find('.cost').text().match(/\d+/)); 
                if (includedCompCost !== "") { sumArray.push(includedCompCost); }
            });
            var total = 0;
            for (var i = 0; i < sumArray.length; i++) {
                var parsedInt = parseInt(sumArray[i]); 
                if (!isNaN(parsedInt) && parsedInt > 0) { 
                   total += parsedInt; 
                } 
            }
            $('.totalcost').text(total);
        });​
Laurence
  • 1,673
  • 11
  • 16
  • That did it, thanks! I had to modify the click/remove class bit to account for the fact that rows were being added dynamically later. I made the add/remove an if/else statement that was executed on click of a single button, and I attached the whole event to the parent table using `on();` Thanks for the help! – ajw-art Aug 24 '12 at 19:50
0

Use parseInt (on the individual pieces you are adding, not just the result) to convert a string to a number, otherwise + will concatenate them instead of adding them.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Thanks! I just got it to work. Here's the code I used: var sumArray = [] $('#calc').click(function(){ $('table tbody tr').each(function() { sumArray.push($(this).find('.cost').text().match(/\d+/)); }); var total = 0; for (var i = 0; i < sumArray.length; i++) { total += parseInt(sumArray[i]); } $('.totalcost').text(total); }); – ajw-art Aug 23 '12 at 19:38
  • Now I've got to figure out how to add in the optional values to the table as well. I managed the above code by cobbling together a half dozen different tutorials, but I'm not sure what I should be looking for to accomplish problem #2. – ajw-art Aug 23 '12 at 19:41