Real time calculation with PHP & array - javascript

For a client i'm currently working on their new system. In this system they can create bookings/invoices and send them to their clients.
On 1 page my client is needed to fill in the price for each container in the qoutation. My client asked me to make a new table column below the container columns with the total prices for all containers. I want to do this real time, so when my client fills in the prices the total price changes.
The only problem I stumble on is this:
I currently have PHP/MySQL function that collect all the containers from a certain quotation out of the database. With a while loop I create the needed html code for each of the containers. I made the input fields (where they fill in the prices) an array by naming the input fields like this:
<td>€ <input type="text" name="msg_container['.$i.'][ocean_freight]" value="'. $quote['ocean_freight'].'" style="width: 100px;" /></td>
The $i variable get's count up for each loop. It starts by 0 and ends when there are no containers left.
To make things a bit more detailed I have created a jsfiddle how the currently page looks like: https://jsfiddle.net/cwfmqbqv/
Now I'm not an expert in javascript so I'm stuck at this point. Long story short, how am I able to calculate all the values in the array in real time?

I've made a simple addition to your fiddle.
It's not complete as I only have time to make one for the Ocean Freight.
JSFiddle
$(document).ready(function() {
$(".oceanIn").keyup(function() {
var total = 0.0;
$.each($(".oceanIn"), function(key, input) {
if(input.value && !isNaN(input.value)) {
total += parseFloat(input.value);
}
});
$("#oceanTotal").html("Total: " + total);
});
});
Also I added some class and id to some of your elements to make it work.
Note
For this one, I used keyup but feel free to use different events like change or blur, or whatever fits your needs.
You should have tried to learn the basics of Javascript before you went and looked for a client.
Also, I think you're confused between a column and a row.

What you want is written in pure js in the following update to your jsfiddle:
JSFiddle
The principal concept here was using the change event on inputs. Furthermore, I didn't change the naming of your inputs but consider better conventions.
In the total function, we get a type of columns we're dealing with (using custom attributes is better than just using input names. eg: column-type="thc") and calculate the total number of each related input.
It uses Regular Expression (RegExp) in your case to find the right column out of input names. Mind that ~~ is just a simple hack for text to integer conversion in JavaScript.
Next we find all inputs and attach an event listener using addEventListener to each for the change event type. In this delegate, we find the appropriate input for total function and span IDs corresponding the column the input represents, again using RegExp but this time implicitly. Then change the corresponding span based on the total return value;

This is similar to the first answer, but more complete, and the addition fires on keyup instead of on blur. It applies to all the columns without needing to create separate functions for each. Here's the fiddle.
Javascript
$(function(){
$(".ocean-input, .bunker-input, .thc-input, .road-input").on("keyup", function()
{
var total = 0;
$("." + $(this).attr('class')).each(function()
{
total += parseFloat($(this).val().replace('', 0).replace(',', '.'));
});
$("#" + $(this).data("total-id")).html(total.toString().replace('.', ','));
});
});
HTML
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="font-family:Arial, sans-serif; color:#000; font-size:12px;">
<thead>
<tr>
<th width="50">Amount</th>
<th>Type</th>
<th>Weight (p/u)</th>
<th>Shipping owned</th>
<th>Ocean Freight</th>
<th>Bunker Surcharge</th>
<th>THC</th>
<th>Road transport</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Container Type 1</td>
<td>1000</td>
<td>No</td>
<td>€ <input type="text" class="ocean-input" data-total-id="ocean-total" name="msg_container[0][ocean_freight]" value="" style="width: 100px;"></td>
<td>€ <input type="text" class="bunker-input" data-total-id="bunker-total" name="msg_container[0][bunker_surcharge]" value="" style="width: 100px;"></td>
<td>€ <input type="text" class="thc-input" data-total-id="thc-total" name="msg_container[0][thc]" value="" style="width: 100px;"></td>
<td>€ <input type="text" class="road-input" data-total-id="road-total" name="msg_container[0][road_transport]" value="" style="width: 100px;"></td>
</tr><tr>
<td>1</td>
<td>Container Type 2</td>
<td>2500</td>
<td>No</td>
<td>€ <input type="text" class="ocean-input" data-total-id="ocean-total" name="msg_container[1][ocean_freight]" value="" style="width: 100px;"></td>
<td>€ <input type="text" class="bunker-input" data-total-id="bunker-total" name="msg_container[1][bunker_surcharge]" value="" style="width: 100px;"></td>
<td>€ <input type="text" class="thc-input" data-total-id="thc-total" name="msg_container[1][thc]" value="" style="width: 100px;"></td>
<td>€ <input type="text" class="road-input" data-total-id="road-total" name="msg_container[1][road_transport]" value="" style="width: 100px;"></td>
</tr> </tbody>
<tfoot>
<tr>
<th width="50"></th>
<th></th>
<th></th>
<th></th>
<th>Total: €<span id="ocean-total"></span></th>
<th>Total: €<span id="bunker-total"></span></th>
<th>Total: €<span id="thc-total"></span></th>
<th>Total: €<span id="road-total"></span></th>
</tr>
</tfoot>
</table>

Related

Checkbox click event

I have a group of checkboxes inside a table where I want to change the value of a different column in the row when the checkbox is checked. I have researched for a solution but nothing I have found seems to solve my problem. I realize that my stumbling block is my unfamiliarity with jquery so any suggestions would help. Ultimately I wish to total the columns where the change has occurred to get a total. So if an answer included ideas about that as well I would not complain. Thanks as always, you are a great group.
HTML
<tr>
<td><input name="amputeeGolfer" type="checkbox" id="amputeeGolfer" value="amputee" onchange="changeFee"/>
<label for="amputeeGolfer">Amputee Golfer</label></td>
<td align="left"><label for="amputeeFee">$50.00</label></td>
<td></td>
<td><input name="amputeeFee" type="number" id="amputeeFee" class="tblRight" size="10" value="0.00"/></td>
</tr>
jquery
<script>
function changeFee(val) {
$('#amputeeFee').val(), "$50.00";
}
</script>
Fully functioning snippet. No jQuery required!
When the onchange event fires, it checks whether the checkbox was just checked or unchecked, and toggles the price accordingly. It can even be combined with all sorts of other checkboxes.
function togglePrice(element,price){
if(element.checked){
document.getElementById("amputeeFee").value = parseInt(document.getElementById("amputeeFee").value) + price;
}else{
document.getElementById("amputeeFee").value = parseInt(document.getElementById("amputeeFee").value) - price;
}
}
<tr>
<td><input name="amputeeGolfer" type="checkbox" id="amputeeGolfer" value="amputee" onchange="togglePrice(this,50);"/>
<label for="amputeeGolfer">Amputee Golfer</label></td>
<td align="left"><label for="amputeeFee">$50.00</label></td>
<td></td>
<td><input name="amputeeFee" type="number" id="amputeeFee" class="tblRight" size="10" value="0"/></td>
</tr>
It works perfectly and you can even set how much the checkbox adds to the cost!
You can get closest tr closest('tr') to assure input in same row with check box and find input with name find("input[name='amputeeFee']") and change value for it.
function changeFee(val) {
var amputeeFee = $(val).closest('tr').find("input[name='amputeeFee']");
if($(val).prop("checked")){
amputeeFee.val(50.00);
}
else{
amputeeFee.val(0);
}
}
function changeFee(val) {
var amputeeFee = $(val).closest('tr').find("input[name='amputeeFee']");
//console.log(amp.length);
if($(val).prop("checked")){
amputeeFee.val(50.00);
}
else{
amputeeFee.val(0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td><input name="amputeeGolfer" type="checkbox" id="amputeeGolfer" value="amputee" onchange="changeFee(this)"/>
<label for="amputeeGolfer">Amputee Golfer</label></td>
<td align="left"><label for="amputeeFee">$50.00</label></td>
<td></td>
<td><input name="amputeeFee" type="number" id="amputeeFee" class="tblRight" size="10" value="0.00"/></td>
</tr>
</table>
To call a JavaScript function like changeFee(val) in an HTML's element event, the funciton has to be called as the same in the script. As all functions in an HTML' event: <element onclick="myFunction()">, and not <element onclick="myFunction"> beacuse it doesn't reconize it's a function in JavaScript.
Then the code will be:
<tr>
<td><input name="amputeeGolfer" type="checkbox" id="amputeeGolfer" value="amputee" onchange="changeFee(this.value)"/>
<label for="amputeeGolfer">Amputee Golfer</label></td>
<td align="left"><label for="amputeeFee">$50.00</label></td>
<td></td>
<td><input name="amputeeFee" type="number" id="amputeeFee" class="tblRight" size="10" value="0.00"/></td>

How to select previous sibling of a parent whose child is last among the input which are not null, using JQuery

I have a little complicated situation here, one which, despite my serious efforts, am unable to find reasonable solution of. So I am placing it here. I have javascript, jQuery and HTML with following details:
var lastDateIndex ='';
function datecheck(){
lastDateIndex = $('td, input[name=date]:not(:empty):last').prev('[name=index]');
alert(lastDateIndex.html());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id='table1'>
<tr id='row1'>
<th>Index</th>
<th>Date</th>
<th>Description</th>
<th>Payment</th>
<th>Balance</th>
</tr>
<tr id='row2' name='row'>
<td name='index'>1</td>
<td name='rowdate'><input type="date" title="date1" name="date" onblur="datecheck();"></td>
<td name='description'><input title="description1" name="description"></td>
<td name='description'><input title="paymentpay1" name="paymentpay"></td>
<td name='description'><input title="balance1" name="balance"></td>
</tr>
<tr id='row3' name='row'>
<td name='index'>2</td>
<td name='rowdate'><input type="date" title="date2" name="date" onblur="datecheck();"></td>
<td name='description'><input title="description2" name="description"></td>
<td name='description'><input title="paymentpay2" name="paymentpay"></td>
<td name='description'><input title="balance2" name="balance"></td>
</tr>
<tr id='row4' name='row'>
<td name='index'>3</td>
<td name='rowdate'><input type="date" title="date3" name="date" onblur="datecheck();"></td>
<td name='description'><input title="description3" name="description"></td>
<td name='description'><input title="paymentpay3" name="paymentpay"></td>
<td name='description'><input title="balance3" name="balance"></td>
</tr>
</table>
This table has numerous input fields and all of them are to be filled by user as per his/hers need. I need to select the td with name='index' inside of last tr where td with input[name='date'] is not null. In other words, if the user has entered date details in input[name='date'] and [title='date1'] inside tr with id='row2' and has left all remaining rows to be blank, I want to select the html inside of name='index' inside tr with id='row2'.
The function I have written above only alerts 1, even if all the rows except the last one are filled. How can I acheive the answer of the html of name='index' of the last tr with empty name='date'?
As far as I know it can't be done using only selectors, so consider the following:
In case the user writes a value in input[name='date'], update its parent TD and add a class/data-* attribute (for instance: addClass('date-isnt-null')).
Use the following selector:
$('.tr:last-child td.date-isnt-null[name="index"]');
If whenever you call your function you want to output all the rows with a date entered, you can use:
function datecheck() {
$('input[name=date]').each(function(i, el) {
if ($(el).val()) {
console.log($(el).parents('tr').find('[name=index]').html());
}
});
}
(not sure to understand the last index bit).
As for Ofir Baruch suggestion, here is a way to go:
$(function() {
$('input[name=date]').bind('blur', function() {
if ($(this).val()){
$(this).parent('td').addClass("dirty");
} else {
// in case the user removes the date
$(this).parent('td').removeClass("dirty");
}
});
});
function datecheck() {
var html = $('.tr:last-child td.dirty[name="index"]').html();
console.log(html);
}
On input date blur and if the user entered a date, we add the class dirty to its parent.

Add new columns with specific ng-model to HTML table

So I am trying to add additional columns to a table inside a form. Adding the columns themselves is not that difficult but I don't know how to go about setting their ng-models.
This is my current code:
(HTML)
<button ng-click="add()" type="button">+ column</button>
<table>
<thead id="inputtablehead">
<th class="theadlabel">(in 1.000 EUR)</th>
<th>{{startyear}}</th>
<th class="NBBCodesHeader">NBB Codes</th>
<th>Source</th>
</thead>
<tbody class="input">
<tr>
<td>number of months</td>
<td>
<input ng-model="input{{startyear}}.NumberMonths" type="text" class="{{startyear}}" required>
</td>
<td class="NBBCodes"></td>
</tr>
<tr>
<td>Fixed assets</td>
<td>
<input ng-model="input{{startyear}}.FixedAssets" class="{{startyear}}" type="text" required>
</td>
<td class="NBBCodes">20/28</td>
</tr>
<tr>
<td>Inventory</td>
<td>
<input ng-model="input{{startyear}}.Inventory" class="{{startyear}}" type="text" required>
</td>
<td class="NBBCodes">3</td>
</tr>
</table>
(JS)
angular.module("inputFields", []).controller("MyTable", function ($scope) {
$scope.startyear = new Date().getFullYear();
var nextyear = new Date().getFullYear() - 1;
$scope.add = function () {
$(".NBBCodesHeader").before("<th>"+nextyear+"</th>");
$(".input .NBBCodes").before('<td><input class='+nextyear+' type="text" required></td>');
nextyear--;
};
});
So in my JS the <input class='+nextyear+' type="text" required> should become something like <input ng-model="input'+nextyear+'.NumberMonths" class='+nextyear+' type="text" required> for the <td> element added next to the 'number of months' row.
I was thinking to give ea row an id in the form of NumberMonths and then look up the id when adding the column.
So my question would be: is this a valid way to do it and how would I get this id? Or am I overthinking it and is there an easier way to do this?
Use standard javascript [] object notation for variable property names.
<input ng-model="input[startyear].Inventory"
You shouldn't do DOM manipulations from a controller. It's not a good practice when working with AngularJS. A good rule to remember that is: don't use jQuery. It's a common mistake when starting working with AngularJS. And, in case you would be completely sure that you need to modify the DOM, do it always from a directive.
About your problem, maybe you can base your solution in create a data structure in your controller (a Javascript Object), and render it through a ng-repeat in your template. This way, if you modify the object (adding a new column), the template will be automatically updated.

how to change value of one input text field (in one html table) based on a specific value of another input text field (present in another html table)

I have one html table which has one row. This row has two TDs which hold their own tables within them (Each having 10 rows with 10 input fields). I want to change value of another respective text field based on value change in first field onblur().
First field-. It takes value from an Array of size 10
<tr>
<td valign="top">
<table width="85%" border="0" cellpadding="2" cellspacing="1" class="inputTable">
<tr>
<td width="60%">
<table width="60%" border="0" cellpadding="0" cellspacing="1">
<c:set var="input1" value="${someForm.value1}"></c:set>
<c:forTokens items="0,1,2,3,4,5,6,7,8,9" delims="," var="count">
<tr>
<td><input id="field1" name="field1" type="text" value="<c:out value="${input1[count]}" />" onblur="setText2(this)" maxlength="20" size="15">
</td>
</tr>
</c:forTokens>
</table>
</td>
</tr>
</table>
</td>
Second field. This requires value chnage on run when respective value changes for above 10 fields
<td valign="top">
<table width="85%" border="0" cellpadding="2" cellspacing="1" class="inputTable">
<tr>
<td width="60%">
<table width="60%" border="0" cellpadding="0" cellspacing="1">
<c:forTokens items="0,1,2,3,4,5,6,7,8,9" delims="," var="count">
<tr>
<td><input id="field2" name="field2" type="text" value="" />" readonly class="readonly" maxlength="1" size="1">
</td>
</tr>
</c:forTokens>
</table>
</td>
</tr>
</table>
</td>
</tr>
Javascript:
<script>
function setText2(element) {
if(element.value)
{
document.getElementById("field2").value = element.value;
}else{
document.getElementById("indicator").value = "";
}
}
</script>
This is running fine. But problem is I am able to identified which field is being changed through this but unable to get reference of target field. This changes value of second fields but always in first row of second table.
Please help me to run this so that if a field changes of table1 , then the repective (same serial) field of table 2 should change. I cant change the table structure due to some project limitations.
getElementById() is selecting the first element with id="field2". You shouldn't give the same id to multiple elements. Try changing the id to correspond to the count, then in your javascript function you can get the field2 input that corresponds to the count of the blurred input.
Replace your field1 code with this:
<input id="field1_${count}" name="field1" type="text" value="${input1[count]}"
onblur="setText2(this)" maxlength="20" size="15"/>
Replace your field2 code with this:
<input id="field2_${count}" name="field2" type="text" value=""
readonly="readonly" class="readonly" maxlength="1" size="1">
Then change your javascript function:
function setText2(element) {
if(element.value)
{
var changedId = element.id;
var elementNumber = changedId.substring(changedId.indexOf('_') + 1);
document.getElementById("field2_" + elementNumber).value = element.value;
}else{
document.getElementById("indicator").value = "";
}
}
As answered by Tap, assign distinct id for each field (of array). The only thing I want to add is, we should use c:out while assigning number to id as given below (otherwise id will not have numbers as being expected rather it will assign string as "field1_${count}" ):
Use:
<input id="<c:out value="field1_${count}" />" name="field1" type="text" value="<c:out value="${input1[count]}" />" onblur="setText2(this)" maxlength="20" size="15"/>
This runs well!! ;)
I am happy; this solved my big problem without affecting structure of the code...
Thanks a lot again Tap, for your suggestion. :)

Get the closest class from a list jquery

It's hard to explain, so I created an example:
jsfiddle
My idea is to change the color of each column when the respective input is in action...
If anyone has a better idea to do this - please let me know!
When I focus the input, I need the current class of the column.
first column input, get the class of the RED column
and the second one, get the class of the BLUE column
and so go's on...
Because if I get the class, then I can manipulate anything with this class.
the code is here:
$(".inputTest").focusin(function(){
var class = $(this).closest('.tableList')
.children().children().children('.auxClass')
.attr('class')
.split(' ')[0];
alert(class);
});
This is the main code, I try alot of stuffs to get, but nothing.
Thanks
First I'd add an outer table to split the page in a left and a right hand side. That way, the inputs below the red border and the inputs below the blue border each have their own table.
Then you can search for the first td below the closest table:
$(".inputTest").focusin(function(){
var class = $(this).closest('table').find('td:eq(0)').attr('class');
alert(class);
});
Click for working jsfiddle example.
Try this:
$(".inputTest").focus(function(){
var class = $(this).closest('table').parent().attr('class');
alert(class);
});
Edit: Oh, i just realised your inputs are not inside your tables, i think you're gonna have a hard time matching them up to the table/column they're under then. You'd need to add a common attribute to identify them by.
As mentioned in other answers your inputs are not actually in the same "columns" as your red/blue bordered tables, but you can make it so they are using the <col> element on the main table, then using the index value you can match your inputs to their column
Working Example
HTML - the only addition is the two <col> elements at the start
<table width="100%" border="1" class='tableList'>
<col span="2" class="left">
<col span="2" class="right">
<tr>
<td class="101 auxClass" width="261px" colspan="2" style="border: solid red;">
<table border="1" cellspacing="1" cellpadding="1" width="100%" height="70px">
<tbody>
<tr>
<td colspan="2">Something</td>
</tr>
<tr>
<td width="78px">Something 2</td>
<td>Total</td>
</tr>
</tbody>
</table>
</td>
<td class="102" width="261px" colspan="2" style="border: solid blue;">
<table border="1" cellspacing="1" cellpadding="1" width="100%" height="70px">
<tbody>
<tr>
<td colspan="2">
Something 3
</td>
</tr>
<tr>
<td width="78px">Something 4</td>
<td width="75px">Total 2</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Result</td>
<td><input type="text" class="inputTest"/></td>
<td>Result</td>
<td><input type="text" class="inputTest"/></td>
</tr>
<tr>
<td>Result</td>
<td><input type="text" class="inputTest"/></td>
<td>Result</td>
<td><input type="text" class="inputTest"/></td>
</tr>
<tr>
<td>Result</td>
<td><input type="text" class="inputTest"/></td>
<td>Result</td>
<td><input type="text" class="inputTest"/></td>
</tr>
</table>
CSS:
col.current {background: #eee;}
jQuery
$(".inputTest").focusin(function(){
var colidx = $(this).closest('td').index();
if (colidx == 1) {
$("col").removeClass('current');
$("col.left").addClass('current');
} else if (colidx == 3) {
$("col").removeClass('current');
$("col.right").addClass('current');
}
});
Your main table is actually 4 columns, and you need to split it into two halfs of two columns each with the input being in the second column of each half
The jQuery is finding the index of the parent td of the input - there are four columns in the main table so the index of a td will either be 0,1,2 or 3 - and the input is either going to be in cell index 1 or cell index 3. When it finds out which one it add a class to the relevant col element to which you can add a background highlight..
Note though that the CSS you can apply to a col element is limited, see: http://www.quirksmode.org/css/columns.html , for the options so it would depend what you want to do
however I think from this you could probably target td index 0 & 1, or td index 2 & 3 if needed

Categories

Resources