1

I want to do some basic math on a Dynamic Html Table that I have which uses JSON data loaded via ajax.

When I try to parseFloat, the code works, however it strips the decimal places from my numbers. I want this to be a restaurant bill application, so the decimals are important. parseFloat.toFixed(2) doesn't work either.

Besides that, I want to be able to select only a few of the rows to have the addition done as a subtotal. I can select the rows on click to highlight them. Once highlighted I could use a if statement to see which rows have the toggled class "Highlighted" and then do the calculation from there. Does anyone know of a more efficient way to do this?

const data = [ 
{pk: 1, Description: "Pizza", Price: "50.00"},
{pk: 2, Description: "Hamburger", Price: "60.00"},
{pk: 3, Description: "Coca Cola", Price: "20.00"},
{pk: 4, Description: "Fanta", Price: "20.00"},
{pk: 5, Description: "Corona", Price: "30.00"},
{pk: 6, Description: "Steak", Price: "100.00"}
]



function showTable(data) {
  var tbl = document.getElementById("food_table")
  var table_data = '';
  var total = 0.00;
  for (i = 0; i < data.length; i++) {
    //To find the total value of the bill!
    total = parseFloat(data[i].Price) + total;
    //To create the rows from JSON Object
    table_data += '<tr id="contentRow">';
    table_data += '<td>' + data[i].pk + '</td>';
    table_data += '<td>' + data[i].Description + '</td>';
    table_data += '<td>' + 'R' + data[i].Price + '</td>';
    table_data += '<td><input class="double" type="checkbox" /></td>';
    table_data += '</tr>';
  }
  tbl.insertAdjacentHTML('afterbegin', table_data);
  tbl.insertAdjacentHTML('beforeend', '<tr id="contentRow">Total Bill = R' + total + '</tr>');
}

$("#food_table").on('click', '#contentRow', function() {
  $(this).toggleClass("highlight");
});

showTable(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table " id="food_table">
  <thead>
    <tr>
      <th>pk</th>
      <th>Description</th>
      <th>Price</th>
      <th></th>
    </tr>
  </thead>
</table>

1
  • 1
    Please click edit then [<>] snippet editor and add relevant script and HTML in a minimal reproducible example. Include an example of data For example what do you mean by select only a few of the rows? Select how? With the checkboxes? What does "does not work either" actually mean? Errors? Wrong results? Commented Oct 26, 2019 at 5:38

3 Answers 3

1

You need to use .text and find using classes instead of IDs which need to be unique

If you only want the rows with the checked boxes, you can do something like

$(".highlight td .double:checked").each

Here is working code

const data = [ 
  {pk: 1, Description: "Pizza", Price: "50.00"},
  {pk: 2, Description: "Hamburger", Price: "60.00"},
  {pk: 3, Description: "Coca Cola", Price: "20.00"},
  {pk: 4, Description: "Fanta", Price: "20.00"},
  {pk: 5, Description: "Corona", Price: "30.00"},
  {pk: 6, Description: "Steak", Price: "100.00"}
]

function showTable(data) {
  var tbl = document.getElementById("food_table")
  var table_data = '';
  for (i = 0; i < data.length; i++) {
    table_data += '<tr class="contentRow">';
    table_data += '<td>' + data[i].pk + '</td>';
    table_data += '<td>' + data[i].Description + '</td>';
    table_data += '<td class="price">' + 'R<span>' + data[i].Price + '</span></td>';
    table_data += '<td><input class="double" type="checkbox" /></td>';
    table_data += '</tr>';
  }
  tbl.insertAdjacentHTML('afterbegin', table_data);
  tbl.insertAdjacentHTML('beforeend', '<tr>Total Bill = R<span id="total">0.00</span></tr>');
}

$(function() {
  $("#food_table").on('click', '.contentRow', function() {
    $(this).toggleClass("highlight");
    var total = 0;
    $(".highlight").each(function() {
      total += +$(this).find(".price>span").text();
    });
    $("#total").text(total.toFixed(2))
  });

  $("#food_table").on('click', '.double', function() {
    var total = 0;
    $(".double:checked").each(function() {
      total += +$(this).find(".price>span").text();
    });
    $("#total").text(total.toFixed(2))
  });

  showTable(data);
});
.highlight {
  background-color: yellow
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table" id="food_table">
  <thead>
    <tr>
      <th>pk</th>
      <th>Description</th>
      <th>Price</th>
      <th></th>
    </tr>
  </thead>
</table>

Sign up to request clarification or add additional context in comments.

14 Comments

Your thoughts are the same as mine :)
Except I only loop over highlighted rows. Apart from that, your code does look remarkably similar to mine, right down to the choice of class and span on the price cell
Thanks very much, this is so useful. my code works now for the subtotal. when trying to get the total i still cant have 2 decimals though? it doesnt look like i can use .text within my table rendering function.
I do not understand what you mean by decimal issues. I see two decimals everywhere in the calculation above...
What subtotal? You code does not have a subtotal anywhere
|
0

const data = [ 
{pk: 1, Description: "Pizza", Price: "50.00"},
{pk: 2, Description: "Hamburger", Price: "60.00"},
{pk: 3, Description: "Coca Cola", Price: "20.00"},
{pk: 4, Description: "Fanta", Price: "20.00"},
{pk: 5, Description: "Corona", Price: "30.00"},
{pk: 6, Description: "Steak", Price: "100.00"}
]



function showTable(data) {
  var tbl = document.getElementById("food_table")
  var table_data = '';
  var total = 0.00;
  var x = 0;
  for (i = 0; i < data.length; i++) {
    //To find the total value of the bill!
    total = Number.parseFloat(x) + total;
    console.log(total);
    //To create the rows from JSON Object
    table_data += '<tr class="contentRow">';
    table_data += '<td>' + data[i].pk + '</td>';
    table_data += '<td>' + data[i].Description + '</td>';
    table_data += '<td class="price">' + 'R' + '<span>' + data[i].Price + '</span></td>';
    table_data += '<td><input class="double" type="checkbox" /></td>';
    table_data += '</tr>';
  }
  tbl.insertAdjacentHTML('afterbegin', table_data);
  tbl.insertAdjacentHTML('beforeend', '<tr>Total Bill = R<span id="total">' + total + '</span></tr>');
}

$("#food_table").on('click', '.contentRow', function() {
  $(this).toggleClass("highlight");
  var total = 0;
  $("#food_table").find('.contentRow').each(function(){
    if($(this).hasClass('highlight')){
      total += parseFloat($(this).find('.price>span').text());
    }
  })
  $('#total').text(total);
});

showTable(data);
.highlight{
  background-color:orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table " id="food_table">
  <thead>
    <tr>
      <th>pk</th>
      <th>Description</th>
      <th>Price</th>
      <th></th>
    </tr>
  </thead>
</table>

Each time a row is selected, iterate over the selected rows and calculate the sum.

Comments

0

I would suggest to use Vue.js instead of jQuery for this case. Instead of manipulating with DOM nodes in Vue.js you just need to create view model and bind it to a template.

<!DOCTYPE html>
<html>
<head>
    <style>
        .highlighted {background: lightyellow}
        table {
            border-collapse: collapse;
            width: 100%;
        }
        th, td {
            padding: 8px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
    </style>
</head>
<body>
  <div id="app">
    <table>
        <thead>
            <tr>
                <th>pk</th>
                <th>Description</th>
                <th>Price</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="item in items" v-bind:key="item.pk" @click="itemClick(item)" :class="rowClass(item)">
                <td>{{item.pk}}</td>
                <td>{{item.Description}}</td>
                <td>{{item.Price}}</td>
                <td>
                    <input type="checkbox" v-model="item.selected" />
                </td>
            </tr>
        </tbody>
    </table>
    <span>Total: {{total}}</span>
  </div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
new Vue({
    el: '#app',
    data() {
        return {
            items: [
                {pk: 1, Description: "Pizza", Price: "50.00", selected: false},
                {pk: 2, Description: "Hamburger", Price: "60.00", selected: false},
                {pk: 3, Description: "Coca Cola", Price: "20.00", selected: false},
                {pk: 4, Description: "Fanta", Price: "20.00", selected: false},
                {pk: 5, Description: "Corona", Price: "30.00", selected: false},
                {pk: 6, Description: "Steak", Price: "100.00", selected: false}
            ]
        }
    },
    computed: {
        total() {
            const result = this.items
                .filter(item => item.selected)
                .map(item => Number(item.Price))
                .reduce((a, b) => a + b, 0)
            return result.toFixed(2);
        }
    },
    methods: {
        rowClass(item) {
            return item.selected ? "highlighted" : "";
        },
        itemClick(item) {
            item.selected = !item.selected;
        }
    }
});
</script>
</body>
</html>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.