0

I've created a table that generates estimates. I've figured out how to add, update line item and estimate total and delete line item and estimate total.

What I am now trying to do is, once the user is done entering data in the table below, I need the user to be able to save this estimate with the estimate primary key to tbl_estimate so... I need to turn each table row into the following JSON format and then submit it to a PHP PDO page for processing.

How can I serializeArray() a table?

// DESIRED JSON FORMAT

[
   {
      "PK_TP_ID":539,
      "DESCRIPTION":"LINE ITEM 1",
      "QUANTITY":"5",
      "UNIT":"SF",
      "COST":"2.24",
      "TOTAL":"11.20",
   },
   {
      "PK_TP_ID":540,
      "DESCRIPTION":"LINE ITEM 2",
      "QUANTITY":"10",
      "UNIT":"SF",
      "COST":"2.01",
      "TOTAL":"20.01"
   },
   {
      "PK_TP_ID":541,
      "DESCRIPTION":"LINE ITEM 3",
      "QUANTITY":"15",
      "UNIT":"SF",
      "COST":"2.60",
      "TOTAL":"39"
   }
]
<!DOCTYPE html>
<html>
<head>
<!-- Import Google Icon Font -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- Import materialize.min.css v1.0.0-alpha.4 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-alpha.4/css/materialize.min.css">

<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

<title>Estimator 1.0</title>

<style>
 
/* table_client_estimate_line_items header width
Header width = Column width --------------------------------------------- */ 
#table_client_estimate_line_items thead tr th:nth-child(1) {
width: auto;
text-align: left;
}
#table_client_estimate_line_items thead tr th:nth-child(2) {
width: auto;
text-align: left;
}
#table_client_estimate_line_items thead tr th:nth-child(3) {
width: auto;
text-align: left;
}
#table_client_estimate_line_items thead tr th:nth-child(4) {
width: auto;
text-align: left;
}
#table_client_estimate_line_items thead tr th:nth-child(5) {
width: auto;
text-align: left;
}
#table_client_estimate_line_items thead tr th:nth-child(6) {
width: auto;
text-align: center;
}
/* End Custom Table Headers---------------------------------------------- */


/* Begin table_client_estimate_line_items cell content alingment ---------------------------------- */

/* td:nth-child(1) = Table Column 1 Cells ------------------------------- */ 
#table_client_estimate_line_items tbody tr td:nth-child(1) {
text-align: left;
/* Client Name Column cells... */
padding-left: 7px !important;
}
/* td:nth-child(2) = Table Column 2 Cells ------------------------------- */ 
#table_client_estimate_line_items tbody tr td:nth-child(2) {
text-align: left;
}
/* td:nth-child(3) = Table Column 3 Cells ------------------------------- */ 
#table_client_estimate_line_items tbody tr td:nth-child(3) {
text-align: left;
}
/* td:nth-child(4) = Table Column 4 Cells ------------------------------- */ 
#table_client_estimate_line_items tbody tr td:nth-child(4) {
text-align: left;
}
/* td:nth-child(5) = Table Column 5 Cells ------------------------------- */ 
#table_client_estimate_line_items tbody tr td:nth-child(5) {
text-align: left;
}
/* td:nth-child(6) = Table Column 6 Cells ------------------------------- */ 
#table_client_estimate_line_items tbody tr td:nth-child(6) {
text-align: center;
}
/* End table_client_estimate_line_items cell content alingment ------------------------------------ */


/* table_client_estimate_line_items cell padding */
#table_client_estimate_line_items tbody tr td {
padding: 0px 5px !important;
}
/* End Custom Padding of Table Cells (td). ------------------------------ */


#estimate_total_refresh {
cursor: pointer;
}

</style>

</head>

<body>


<!-- Begin container -->
<div class="container">


<!--
888888    db    88""Yb 88     888888 
  88     dPYb   88__dP 88     88__   
  88    dP__Yb  88""Yb 88  .o 88""   
  88   dP""""Yb 88oodP 88ood8 888888 
-->


<!-- Begin row -->
<div class="row">

<!-- Begin input/column -->
<div class="col s12">

<!-- Begin table -->
<table id="table_client_estimate_line_items" class="striped col s12">

<!-- Begin table head -->
<thead>
<tr>
<th>DESCRIPTION</th>
<th>&nbsp;</th>
<th>UNIT</th>
<th>COST</th>
<th>SUBT</th>
<th>&nbsp;</th>
</tr>
</thead>
<!-- ./ End table head -->


<tfoot>
<th>&nbsp;</th>

<th>&nbsp;</th>
<th>&nbsp;</th>
<th>TOTAL</th>
<th id="estimate_total" class="red-text">$0,00</th>
<th>&nbsp;</th>
</tfoot>


<!-- Begin table body -->
<tbody>

<tr>
<td class="red-text" style="font-size: 0.85rem; font-weight: bold;">LINE ITEM 1</td>
<td><input id="" name="" value="" placeholder="" type="text" style="height: 25px;" class="red-text line_item_quantity"></td>
<td>SF</td>
<td class="line_item_cost">1.33</td>
<td class="line_item_total">0.00</td>
<td><a class="waves-effect waves-light btn-flat red-text lighten-1 btn_delete_table_row"><i class="material-icons md-24">close</i></a></td>
</tr>

<tr>
<td class="red-text" style="font-size: 0.85rem; font-weight: bold;">LINE ITEM 2</td>
<td><input id="" name="" value="" placeholder="" type="text" style="height: 25px;" class="red-text line_item_quantity"></td>
<td>SF</td>
<td class="line_item_cost">2.01</td>
<td class="line_item_total">0.00</td>
<td><a class="waves-effect waves-light btn-flat red-text lighten-1 btn_delete_table_row"><i class="material-icons md-24">close</i></a></td>
</tr>

<tr>
<td class="red-text" style="font-size: 0.85rem; font-weight: bold;">LINE ITEM 3</td>
<td><input id="" name="" value="" placeholder="" type="text" style="height: 25px;" class="red-text line_item_quantity"></td>
<td>SF</td>
<td class="line_item_cost">0.52</td>
<td class="line_item_total">0.00</td>
<td><a class="waves-effect waves-light btn-flat red-text lighten-1 btn_delete_table_row"><i class="material-icons md-24">close</i></a></td>
</tr>

</tbody>
<!-- ./ End table body -->

</table>
<!-- ./ End table -->

</div>
<!-- ./ End input/column -->

</div>
<!-- ./ End row -->

</div>
<!-- ./ End container -->

<!-- 1. Import jquery.min.js v3.2.1         JS !-->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- ***BEFORE*** materialize.js !-->

<!-- ***AFTER*** jquery.min.js !-->
<!-- 2. Import materialize.min.js v1.0.0-alpha.4  JS !-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-alpha.4/js/materialize.min.js"></script>

<!-- BEGIN Before DOCUMENT.READY -->
<script>

// Initialization
init_1();

// begin function init_1()
function init_1 () {

// Create global timer outside keyup scope.
var timer;

// Bind keyup event to all input type=text in #table_client_estimate_line_items > tbody tr td. 
$("#table_client_estimate_line_items > tbody tr td input[type=text]").keyup(function(event) {

// reference to the inpout text we are currently in...
var self = $(this);

// line_item_quantity
line_item_quantity = $(this).val();
// Trim it..
line_item_quantity = $.trim(line_item_quantity);

// parent_line_item_cost td text...
var parent_line_item_cost = $(this).closest('tr').children('.line_item_cost').text();

// If timer has been set but user still typing...
if (timer) {
// Reset timer and abort function call.
clearTimeout(timer);
}
// Set timer to tick in 1 second for 1 second then call function and stop.
timer = setTimeout(function(event) {

// BEGIN REFRESH ESTIMATE LINE ITEM TOTAL
let parent_line_item_total = (line_item_quantity * parent_line_item_cost);

self.closest('tr').children('.line_item_total').text(parent_line_item_total.toFixed(2));
// END REFRESH ESTIMATE LINE ITEM TOTAL

// BEGIN REFRESH ESTIMATE TOTAL

// goblal var line_item_cost_sum...
var line_item_total_sum = 0;

// for each table td cell with class .line_item_total...
$('.line_item_total').each(function(){

// reference to current td text...
let td_text = $(this).text();
// SUM ONLY if td text is a number...
if(!isNaN(td_text) && td_text.length != 0) {
// if it is a number, add this number to global var line_item_total_sum.
line_item_total_sum += parseFloat(td_text);
}

});

// finally, output global var line_item_total_sum to element id #estimate_total located in table > tfoot
$('#estimate_total').empty().append('$', line_item_total_sum.toFixed(2));
console.log('Line Items Totals: $' + line_item_total_sum.toFixed(2));

// END REFRESH ESTIMATE TOTAL

}, 1000); //wait 1000 milliseconds before triggering event.
});


}
// END function init_1()


// CLICK Events --------------------------------------------------------------

// Remove line item from table_client_estimate_line_items.
$(document).on('click','a.btn_delete_table_row', function(event) {
// Deletes parent table row.
$(this).closest('tr').remove();


// Recalculate Estimate Totals..
recalculateEstimateTotal();

});


// BEGIN function recalculateEstimateTotal()
function recalculateEstimateTotal () {

// Create global timer outside keyup scope.
var timer;

// If timer has been set but user still typing...
if (timer) {
// Reset timer and abort function call.
clearTimeout(timer);
}
// Set timer to tick in 1 second for 1 second then call function and stop.
timer = setTimeout(function(event) {


// BEGIN REFRESH ESTIMATE TOTAL

// goblal var line_item_cost_sum...
var line_item_total_sum = 0;

// for each table td cell with class .line_item_total...
$('.line_item_total').each(function(){

// reference to current td text...
let td_text = $(this).text();
// SUM ONLY if td text is a number...
if(!isNaN(td_text) && td_text.length != 0) {
// if it is a number, add this number to global var line_item_total_sum.
line_item_total_sum += parseFloat(td_text);
}

});

// finally, output global var line_item_total_sum to element id #estimate_total located in table > tfoot
$('#estimate_total').empty().append('$', line_item_total_sum.toFixed(2));
console.log('Line Items Totals: $' + line_item_total_sum.toFixed(2));

// END REFRESH ESTIMATE TOTAL

}, 1000); //wait 1000 milliseconds before triggering event.
//});


}
// END function recalculateEstimateTotal()

// END Before DOCUMENT.READY -->
</script>

<!-- BEGIN DOCUMENT.READY -->
<script>
$(document).ready(function() {

});
// END DOCUMENT.READY -->
</script>

</body>
</html>
suchislife
  • 4,251
  • 10
  • 47
  • 78

1 Answers1

1

.serializeArray() would only works if your table contained form elements. You only have one column with form elements.

Instead what you can do is build the JSON by mapping each row to an object.

$(function() {

  $('button').click(function () {
    // build json
    var json = $('#table_client_estimate_line_items tbody tr').map(function () {
      var id = null, // no idea where you got ID
        desc = $('td', this).eq(0).text(),
        qty = parseInt($('td', this).eq(1).find('input').val(), 10) || 0,
        unit = $('td', this).eq(2).text(),
        cost = parseFloat($('td', this).eq(3).text()) || 0,
        total = qty * cost;
    
      return {
        "PK_TP_ID": id,
        "DESCRIPTION": desc,
        "QUANTITY": qty,
        "UNIT": unit,
        "COST": cost,
        "TOTAL": total
      }
    }).get();

    console.log(json);
  });
  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button>JSON</button>

<br><br>

<!-- Begin table -->
<table id="table_client_estimate_line_items" class="striped col s12">
  <!-- Begin table head -->
  <thead>
    <tr>
      <th>DESCRIPTION</th>
      <th>&nbsp;</th>
      <th>UNIT</th>
      <th>COST</th>
      <th>SUBT</th>
      <th>&nbsp;</th>
    </tr>
  </thead>
  <!-- ./ End table head -->
  <tfoot>
    <th>&nbsp;</th>
    <th>&nbsp;</th>
    <th>&nbsp;</th>
    <th>TOTAL</th>
    <th id="estimate_total" class="red-text">$0,00</th>
    <th>&nbsp;</th>
  </tfoot>
  <!-- Begin table body -->
  <tbody>
    <tr>
      <td class="red-text" style="font-size: 0.85rem; font-weight: bold;">LINE ITEM 1</td>
      <td><input id="" name="" value="5" placeholder="" type="text" style="height: 25px;" class="red-text line_item_quantity"></td>
      <td>SF</td>
      <td class="line_item_cost">1.33</td>
      <td class="line_item_total">0.00</td>
      <td><a class="waves-effect waves-light btn-flat red-text lighten-1 btn_delete_table_row"><i class="material-icons md-24">close</i></a></td>
    </tr>
    <tr>
      <td class="red-text" style="font-size: 0.85rem; font-weight: bold;">LINE ITEM 2</td>
      <td><input id="" name="" value="10" placeholder="" type="text" style="height: 25px;" class="red-text line_item_quantity"></td>
      <td>SF</td>
      <td class="line_item_cost">2.01</td>
      <td class="line_item_total">0.00</td>
      <td><a class="waves-effect waves-light btn-flat red-text lighten-1 btn_delete_table_row"><i class="material-icons md-24">close</i></a></td>
    </tr>
    <tr>
      <td class="red-text" style="font-size: 0.85rem; font-weight: bold;">LINE ITEM 3</td>
      <td><input id="" name="" value="15" placeholder="" type="text" style="height: 25px;" class="red-text line_item_quantity"></td>
      <td>SF</td>
      <td class="line_item_cost">0.52</td>
      <td class="line_item_total">0.00</td>
      <td><a class="waves-effect waves-light btn-flat red-text lighten-1 btn_delete_table_row"><i class="material-icons md-24">close</i></a></td>
    </tr>
  </tbody>
  <!-- ./ End table body -->
</table>
<!-- ./ End table -->

TODO Add rounding.

Mikey
  • 6,728
  • 4
  • 22
  • 45
  • Sweet reply man! Yes! So much yes! I've kindly submitted an edit to account for TODO Add rounding. `.toFixed(2)` for a couple digits after the decimal. – suchislife Mar 16 '18 at 05:31
  • May I ask, what's with the `).get();` part of your sample? – suchislife Mar 16 '18 at 15:54
  • @ASPiRE The return value of `.map()` is a jQuery object, which contains an array. Using `.get()` on the result changes it into a basic array. – Mikey Mar 16 '18 at 18:36
  • I see. Is it more ideal than running `Stringify()` on it? Or just another way? – suchislife Mar 16 '18 at 18:37
  • 1
    @ASPiRE I don't think `JSON.stringify()` would be much use here. This solution is straightforward as you just want to convert a set of table rows into an array of objects -- perfect use case for `.map()`. – Mikey Mar 16 '18 at 18:49