This is related to this thread. I am adding line items with auto calculations according to the selection of price, quantity, discount and tax.
Only for tax I pass values as 1_2, i.e. both id and tax rate. So for the first line item I get a proper value for tax, but from the second onwards, whatever tax I select, it takes the first item's tax value. I don't see what I am doing wrong.
Here is my HTML through which I select the values:
<td>
<select name="tax[]" class="form-control tax" id="tax_1" style="width:80px;">
<option value="">Tax</option>
<?php
$s1 = mysqli_query($con, "select * from taxes");
while($s2 = mysqli_fetch_array($s1)) {
$options .= "<option value='". $s2['tax_id']."_".$s2['rate']."'>"
.$s2['name'].'-'.$s2['rate'] . "</option>";
?>
<option value="<?php echo $s2['tax_id']."_".$s2['rate']; ?>">
<?php echo $s2['name'].'-'.$s2['rate']; ?></option>
<?php
}
?>
</select>
</td>
</tr>
My script:
$(".addmore").on('click', function() {
count = $('table tr').length - 1;
var data = "<tr><td><input type='checkbox' class='case'/></td><td><input class='form-control' type='text' id='productname_" + i + "' name='productname[]'/></td><td><input class='form-control' type='text' id='productcode_" + i + "' name='productcode[]'/></td> <td><textarea class='form-control' id='description_"+ i + "' name='description[]'></textarea></td><td><select class='form-control uom' id='uom_" + i + "' name='uom[]'><option value=''>UOM</option>" + options1 + "</select></td><td><input class='form-control price' type='text' id='price_" + i + "' name='price[]'/></td><td><select class='form-control tax' id='tax_" + i + "' name='tax[]'><option value=''>Tax</option>" + options + "</select></select></td><td><input class='form-control quantity' type='text' id='quantity_" + i + "' name='quantity[]'/></td><td><input class='form-control discount' type='text' id='discount_" + i + "' name='discount[]'/></td><td><input class='form-control amount' type='text' id='amount_" + i + "' name='amount[]'/></td><td><input class='form-control tamount' type='text' id='tamount_" + i + "' name='tamount[]'/></td></tr>";
$('table').append(data);
row = i;
$('#productname_' + i).autocomplete({
source: function(request, response) {
$.ajax({
url: 'ajax.php',
dataType: "json",
method: 'post',
data: {
name_startsWith: request.term,
type: 'items_table',
row_num: row
},
success: function(data) {
response($.map(data, function(item) {
var code = item.split("|");
return {
label: code[0],
value: code[0],
data: item
}
}));
}
});
},
$('body').on('change', '.quantity,.price,.discount,.tax', function() {
var tr = $(this).parent().parent();
var qty = tr.find('.quantity').val();
var price = tr.find('.price').val();
var taxVal= $('.tax').val();
var tax_id=taxVal.split('_')[0];
var rate=taxVal.split('_')[1];
// Here from 2nd line item i am getting 1st line items value for tax.
var dis = tr.find('.discount').val();
var amt = (qty * price) - (qty * price * dis) / 100;
var tax1 = (amt * (rate / 100));
tax1 = Number((tax1).toFixed(2));
tr.find('.tamount').val(tax1);
ttotal();
tr.find('.amount').val(amt);
total();
//tr.find('.ttotal1').val();
});
I see.
This is because you're selecting the .tax selector like so:
var taxVal= $('.tax').val();
You should use $(this) to grab it. Because the way you're doing it, it'll always grab the first one.
Please see this jsfiddle for an example
In short:
$('.tax'); will select any element with the .tax class within the DOM.
When you use any type of binding, this will be the element that triggered the binding (The change event)
So, by grabbing $(this), you'll be grabbing the element that has actually been changed. By grabbing $('.tax'), you'll just grab any .tax element that is in the DOM.
Hope this helps :)
Example html
<select class="tax" id="tax">
<option value="1_2">1_2</option>
<option value="1_3">1_3</option>
<option value="2_2">2_2</option>
</select>
<select class="tax" id="tax">
<option value="3_2">3_2</option>
<option value="3_3">3_3</option>
<option value="3_2">3_2</option>
</select>
Example jQuery
$('.tax').on('change', function() {
var $changedInput = $(this);
var value = $changedInput.val();
var aValues = value.split('_');
var tax_id = aValues[0];
var rate = aValues[1];
alert("tax_id: " + tax_id + " Rate:" + rate );
});
p.s. in your own code, you are already grabbing the parentrow for the other fields in order to find them, so why not do this for .tax also?
tr.find('.tax').val();
"So for the first line item I get a proper value for tax, but from the
second onwards, whatever tax I select, it takes the first item's tax
value."
As Far I See, You are not taking the current object values. You always referring the class name. Since, every inputs having ID ( separated by _ ). You can fetch the ID of that particular Input field and can split to get exact/current ID of it. Using this current ID, you can find other input values too.
Updated Code
$('body').on('change', '.quantity,.price,.discount,.tax', function() {
var tr = $(this).parents('tr');
var id_clicked = $(this).attr('id');
var current_id = id_clicked.split("_")[1];
var qty = tr.find("#quantity_"+current_id).val();
var dis = tr.find("#tax_"+current_id).val();
var price = tr.find("#price_"+current_id).val();
var taxVal= tr.find("#tax"+current_id).val();
var rate = taxVal.split('_')[1];
var amt = (qty * price) - (qty * price * dis) / 100;
var tax1 = (amt * (rate / 100));
tax1 = Number((tax1).toFixed(2));
tr.find('#tamount_'+current_id).val(tax1);
tr.find('#tamount_'+current_id).val(amt);
});
Related
I have a form with two inputs where the user has to select a number from two different sets. The first one is from 1 to 100. The second one is from 1 to 500, but I need to show only the remaining values above the number selected in the first input. Let's say I have a script like this:
<?php
echo "<form action='process.php' method='post'>";
echo "<select id='first_set' name='first_set'>";
echo "<option value='' disabled selected hidden>select how many</option>";
for ($i = 1; $i <= 100; $i ++) {
echo "<option value='" . $i . "'>" . $i . "</option>";
}
echo "</select>";
echo "<select id='second_set' name='second_set'>";
?>
<script type="text/javascript">
$(document).ready(function(){
$('#first_set').on('change',function(){
var numFirstSet = $(this).val();
if(numFirstSet){
var topSecondSet = 500;
var numRemaining = topSecondSet - numFirstSet;
for (var a = numRemaining; a < topSecondSet; a ++) {
var numToDisplay = a;
$('#second_set').html('<option value="numToDisplay">numToDisplay</option>');
}
}else{
$('#second_set').html('<option value="">Select first a value from the set before!</option>');
}
});
});
</script>
<?php
// the submit button
echo "</form>";
?>
But it doesn't work. The second_set select sadly displays the word "numToDisplay", not the calculated value (var numToDisplay) nor the text "Select first a value from the set before!".
Edit: after some suggestions, I've tried with
$('#second_set').html('<option value="' + numToDisplay + '">' + numToDisplay + '</option>');
but got a strange result: after a select done in first_set, the numToDisplay value is shown but it's always 499. That is topSecondSet - 1 ! And no set of values.
I've tried to figure out a solution and wrote this code:
<script type="text/javascript">
$(document).ready(function(){
$('#first_set').on('change',function(){
var sel_box = document.getElementById("second_set");
var numFirstSet = $(this).val();
sel_box.selectedIndex = 0;
if(numFirstSet){
var topSecondSet = 100;
var startNum = numFirstSet + 1;
for (var a = startNum; a <= topSecondSet; a ++) {
var numToDisplay = a;
var option = document.createElement("option");
option.text = numToDisplay;
sel_box.add(option);
}
}else{
var selectfirstText = "Select first a value from the set before!";
sel_box.html = '<option value="">' + selectfirstText + '</option>';
}
});
});
</script>
Now second_set is populated after the change in first_set , but got two problems:
1) the items in second_set start from numFirstSet*10 instead of numFirstSet+1;
2) each time a change is made in first_set selection, a new set of options is added instead of substitute the previous set, despite the row
sel_box.selectedIndex = 0;
that has the goal of resetting the options before adding the new ones.
3) the code
var selectfirstText = "Select first a value from the set before!";
sel_box.html = '<option value="">' + selectfirstText + '</option>';
gives no output, it simply does not work.
Any idea to solve the three problems as above?
Here is a solution that appends a child not using Jquery. Look at Emiel Zuurbiers comments as well. I would also be careful using if(numFirstSet) becuase if the value is 0 it will evaluate as false. I think your intended result should have a check after document.ready and not in the onchange function. That way your "Select first value" option is there at runtime.
let firstSet = document.getElementById("first_set");
$(document).ready(function() {
if (firstSet.value === "null") {
$("#second_set").html(
'<option value="">Select first a value from the set before!</option>'
);
}
$("#first_set").on("change", function() {
var numFirstSet = parseInt($(this).val());
// console.log(numFirstSet);
$("#second_set").html("");
var topSecondSet = 50;
var numRemaining = topSecondSet - numFirstSet;
for (var a = numRemaining; a < topSecondSet; a++) {
let opt = document.createElement("option");
opt.innerHTML = a;
opt.value = a;
document.getElementById("second_set").append(opt);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="first_set">
<option selected disabled value="null">Nothing</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<br /><br />
<select id="second_set"> </select>
This is code i have written to get checkbox value and add rows
can anyone have look on this and find what's the problem with this code
$('.dm_list_data').on('change', function() {
var $sel = $(this);
val = $(this).val();
$opts = $sel.children();
prevUnselected = $sel.data('unselected');
var currUnselected = $opts.not(':selected').map(function() {
return this.value
}).get();
var currSelected = $('.dm_list_data').val();
var post_data = {
'deliver_id': currSelected
}
console.log(post_data);
$.ajax({
type: "POST",
url: base_url + 'curriculum/topicadd/get_deliver_method_details',
data: post_data,
datatype: "JSON",
success: function(msg) {
var JSONObject = JSON.parse(msg);
JSONObject.forEach(function(element) {
var delivery_mtd_name = element.delivery_mtd_name;
var ftfl_hours = element.ftfl_hours;
var assessment_hours = element.assessment_hours;
var slt_hours = element.slt_hours;
var markup = "<tr><td><input type='text' name='record' value='" + delivery_mtd_name + "'></td><td><input type='text' name='record' value='" + ftfl_hours + "'></td><td><input type='text' name='record' value='" + assessment_hours + "'></td><td><input type='text' name='record' value='" + slt_hours + "'></td></tr>";
$("table tbody").append(markup);
});
}
});
});
Rows are getting multipe if i checked thrice please go through image
I will suggest create a hashmap which contains checked elements. Triggering Onchange will just update your hashmap and call a function to create/delete rows. hashmaps are way faster and easy to code.Make your keys as id of table row. Depending on check or uncheck condition, call function which is required.
Before you create a new element and append, just check whether it exists. If does not exist, then add it. Just add id for text box and if condition. Below code may have syntax error, i just tested in browser. Maybe little tweaks needed.
$('.dm_list_data').on('change', function() {
var $sel = $(this);
val = $(this).val();
$opts = $sel.children();
prevUnselected = $sel.data('unselected');
var currUnselected = $opts.not(':selected').map(function() {
return this.value
}).get();
var currSelected = $('.dm_list_data').val();
var post_data = {
'deliver_id': currSelected
}
console.log(post_data);
$.ajax({
type: "POST",
url: base_url + 'curriculum/topicadd/get_deliver_method_details',
data: post_data,
datatype: "JSON",
success: function(msg) {
var JSONObject = JSON.parse(msg);
JSONObject.forEach(function(element) {
var delivery_mtd_name = element.delivery_mtd_name;
var ftfl_hours = element.ftfl_hours;
var assessment_hours = element.assessment_hours;
var slt_hours = element.slt_hours;
if($('#'+delivery_mtd_name).length==0)///added this line
{
//updated below line
var markup = "<tr><td><input type='text' name='record' value='" + delivery_mtd_name + "' id='" + delivery_mtd_name + "'></td><td><input type='text' name='record' value='" + ftfl_hours + "'></td><td><input type='text' name='record' value='" + assessment_hours + "'></td><td><input type='text' name='record' value='" + slt_hours + "'></td></tr>";
$("table tbody").append(markup);
}
});
}
});
});
I am able to display the name, price and fetch the quantity previously entered into the database. On page load, i want the script to calculate the total by multiplying the price and quantity of each selected item and adding up the sub-totals of each item to get the grand total.
how can i achieve this?
<div class="panel_container"></div>
<script type="text/javascript">
$( document ).ready(function() {
#foreach ($items->products as $product)
var product = $('#{!! $product->id !!}');
var selectedItems = JSON.parse(product.attr('data-products'));
if(product.prop("checked") ) {
$('.panel_container').append(
'<div class="container">' +
'<p class="name">' + product.name + '</p>' +
'<p class="price" data-price="' + product.price + '">' + product.price + '</p>' +
'<p class="sub-total"><span class="sub-total" name="sub-total" id="sub-total"></span></p>'+
'<input type="text" class="form-control quantity" placeholder="qty" name="quantity[]" value="{!!$product->pivot->quantity!!}" required/>'+
'</div>'
)
} else {
//clear selected item
}
#endforeach
calculate();
});
var sub-total = 0;
var calculate = function() {
var ship_container = $('.panel_container').closest('div');
var quantity = Number($('.quantity').val());
var price = Number($('.panel_container').closest('div').find('.price').data('price'));
ship_container.find(".sub-total span").text(quantity * price);
}
</script>
Your code must be modified to run for each product.
var grandTotal = 0;
var calculate = function() {
// for each product
$('.panel_container .container').each(function() {
var product = $(this),
quantity = Number(product.find('.quantity').val()), // get quantity
price = Number(product.find('.price').data('price')), // get price
total = quantity * price; // calculate product total
product.find('.sub-total span').text(total); // show product total
grandTotal += total; // add to grand total
});
// use the grandTotal here..
alert('Grand total: ' + grandTotal);
}
Additionally, id attributes are required to be unique in the html so you should remove the id="sub-total" from the loop.
Good day,
I have a table where you can dynamically add/remove rows, on each row you can add an select an item from the list its working perfectly at the moment, what I want to add is for it to retain the added rows and its values even if I page reload my browser?
I have seen on my research that you can attain it by using cookies/localStorage,but would be okay if I store many items on it?
heres my table looks like:
my JS:
function addRow(){
var rowCount = document.getElementById('tblItemList').rows.length - 1 ;
var rowArrayId = rowCount ;
var toBeAdded = document.getElementById('toBeAdded').value;
if (toBeAdded=='')
{ toBeAdded = 2; }
else if(toBeAdded>10)
{
toBeAdded = 10;
}
for (var i = 0; i < toBeAdded; i++) {
var rowToInsert = '';
rowToInsert = "<tr><td><input id='itemName"+rowArrayId+"' required name='product["+rowArrayId+"][name]' class='form-control col-lg-5 itemSearch' type='text' placeholder='select item' />"+
"<input type='hidden' class='rowId' value='"+rowArrayId+"'>"+
"<input type='hidden' name='product[" + rowArrayId + "][itemId]' id='itemId'></td>";
$("#tblItemList tbody").append(
rowToInsert+
"<td><textarea readonly name='product["+rowArrayId+"][description]' class='form-control description' rows='1' ></textarea></td>"+
"<td><input type='number' min='1' max='9999' name='product["+rowArrayId+"][quantity]' class='qty form-control' required />"+
"<input id='poItemId' type='hidden' name='product[" + rowArrayId + "][poContentId]'></td>"+
"<td><input type='number' min='1' step='any' max='9999' name='product["+rowArrayId+"][price]' class='price form-control' required /></td>"+
"<td class='subtotal'><center><h3>0.00</h3></center></td>"+
"<input type='hidden' name='product["+rowArrayId+"][delete]' class='hidden-deleted-id'>"+
"<td class='actions'><a href='#' class='btnRemoveRow btn btn-danger'>x</a></td>"+
"</tr>");
var rowId = "#itemName"+rowArrayId;
$(rowId).select2({
placeholder: 'Select a product',
formatResult: productFormatResult,
formatSelection: productFormatSelection,
dropdownClass: 'bigdrop',
escapeMarkup: function(m) { return m; },
formatNoMatches: function( term ) {
$('.select2-input').on('keyup', function(e) {
if(e.keyCode === 13)
{
$("#modalAdd").modal();
$(".select2-input").unbind( "keyup" );
}
});
return "<li class='select2-no-results'>"+"No results found.<button class='btn btn-success pull-right btn-xs' onClick='modal()'>Add New Item</button></li>";
},
minimumInputLength:1,
ajax: {
url: '/api/productSearch',
dataType: 'json',
data: function(term, page) {
return {
q: term
};
},
results: function(data, page) {
return {results:data};
}
}
});
rowArrayId = rowArrayId + 1;
};
function productFormatResult(product) {
var html = "<table><tr>";
html += "<td>";
html += product.itemName ;
html += "</td></tr></table>";
return html;
}
function productFormatSelection(product) {
var selected = "<input type='hidden' name='itemId' value='"+product.id+"'/>";
return selected + product.itemName;
}
$(".qty, .price").bind("keyup change", calculate);
};
the problem here is whenever Im refreshing the page the Items that I added will also be lost as well as those rows that I've added, any suggestions please? Thanks you very much for your time! Have a nice Day!
Your best bet here would be to cookies to store json data.
Your best bet here would be to cookies to store json data.
function storeRowData() {
var data = [];
$('.TABLE_NAME tr').each(function () {
var $this = $(this),
pname = $this.find(PRODUCT_NAME_INPUT).val(),
desc = $this.find(PRODCUT_DESC_INPUT).val(),
quant = $this.find(PRODUCT_QUANTITY_INPUT).val(),
price = $this.find(PRODUCT_PRICE_INPUT).val();
var temp = { productName: pname, description: desc, quantity: quant, price: price };
data.push(temp);
});
$.cookie('Table_Rows', JSON.stringify(data), {OPTIONS});
}
Now whenever you add or remove rows, you can call this. And when you reload page just read the cookie and parse the string back to JSON and traverse and call addrow for each row.
NOTE: Be sure to read full documentation on jquery.cookie() Here
You can use window.location.reload(true) and $( document ).ready function where you can get current no. of rows.Define row count & column count variable as a global variable.
location.reload(true);
var rowCount,rowArrayId,toBeAdded ;
$(document).ready(function() {
rowCount= document.getElementById('tblItemList').rows.length - 1 ;
rowArrayId = rowCount ;
toBeAdded = document.getElementById('toBeAdded').value;
});
I'm trying to get a JQuery function to pick up specific changes to a form and then plug the information into equations so that each section of the form has answers created for it automatically. I got the first part of it to work (Quantity for Posts) but can't get the second part to work (Quantity for Rails). If anyone can point out or explain where I went wrong and how I could fix it it would be greatly appreciated! Thanks!
Here is a JSFiddle - http://jsfiddle.net/gv0029/ncn42/1/
HTML:
<fieldset id="fence">
<div name="inputFence" class="inputFence">
<legend><strong>Fence Description</strong>
</legend>
<label>Footage:
<input name="footage_1" class="footage" />
</label>
<select name="fenceHeight_1" class="fenceHeight">
<option value="select">Select Fence Height</option>
<option value="6" id="fH6">6 Ft.</option>
<option value="8" id="fH8">8 Ft.</option>
</select>
<legend><strong>Post Type</strong>
</legend>
<label>Post Quantity:
<input name="postQuantity_1" class="postQuantity" />
</label>
<legend><strong>Rail Type</strong>
</legend>
<select name="6foc_1" class="6foc">
<option value="select">6 Ft. on Center?</option>
<option value="no">No</option>
<option value="yes">Yes</option>
</select>
<label>Quantity:
<input class="railQuantity" name="railQuantity_1" />
</label>
</fieldset>
<div>
<input type="button" id="btnAddFence" value="Add Another Fence" />
<input type="button" id="btnDelFence" value="Remove Fence" />
</div>
</form>
JS:
//Quantity for Posts
$(document.body).on('keypress keydown keyup change', '[class^="footage"] ', function () {
var footage = parseFloat($(this).val(), 10);
var total = '';
var parts = $(this).attr('name').split("_");
var fenceNumber = parts[1];
if (!isNaN(footage)) {
total = Math.ceil(footage / 7);
$(":input[name='postQuantity_" + fenceNumber + "'" + ']').val(total.toString());
} else {
$(":input[name='postQuantity_" + fenceNumber + "'" + ']').val("");
}
});
//Quantity for Rails
$(document.body).on('keypress keydown keyup change', '[class^="footage"] [class^="fenceHeight"] [class^="6foc"]', function () {
var parts = $(this).attr('name').split("_");
var fenceNumber = parts[1];
var footage = parseFloat($(":input[name='footage_" + fenceNumber + "'" + ']').val(), 10);
var fenceHeight = $(":input[name='fenceHeight_" + fenceNumber + "'" + ']').val();
var railQuantity = $(":input[name='railQuantity_" + fenceNumber + "'" + ']').val();
var total = '';
var sfoc = $(":input[name='6foc_" + fenceNumber + "'" + ']').val();
if (fenceHeight = !NaN) {
if (sfoc == "no") {
if (fenceHeight == '8') {
total = (Math.ceil(footage / 8) * 4);
}
if (fenceHeight == '6') {
total = (Math.ceil(footage / 8) * 3);
}
railQuantity.val(total);
}
if (sfoc == "yes") {
if (fenceHeight == '8') {
total = (Math.ceil(footage / 12) * 4);
railQuantity.val(total);
}
if (fenceHeight == '6') {
alert("Error: 6ft on Center cannot use 6ft posts");
railQuantity.val("ERROR");
}
}
} else {
railQuantity.val("");
}
});
//Dynamic Fence Input Fields
$('#btnAddFence').click(function () {
// create the new element via clone()
var newElem = $('.inputFence:last').clone();
// insert the new element after the last "duplicable" input field
$('.inputFence:last').after(newElem);
// enable the "remove" button
$('#btnDelFence').removeAttr('disabled');
//get the input name and split into array (assuming your clone is always last)
var parts = $('.fenceHeight:last').attr('name').split("_");
//change the second element of the array to be one higher
parts[1]++;
//join back into a string and apply to the new element
$('.fenceHeight:last').attr('name', parts.join("_"));
//do the same for other two inputs
parts = $('.postQuantity:last').attr('name').split("_");
parts[1]++;
$('.postQuantity:last').attr('name', parts.join("_"));
parts = $('.footage:last').attr('name').split("_");
parts[1]++;
$('.footage:last').attr('name', parts.join("_"));
parts = $('.6foc:last').attr('name').split("_");
parts[1]++;
$('.6foc:last').attr('name', parts.join("_"));
});
$('#btnDelFence').click(function () {
//remove the last inputFence
$('.inputFence:last').remove();
// if only one element remains, disable the "remove" button
if ($('.inputFence').length == 1) $('#btnDelFence').attr('disabled', 'disabled');
});
$('#btnDelFence').attr('disabled', 'disabled');
You had a few problems.
First was this line:
$(document.body).on('keypress keydown keyup change', '[class^="footage"] [class^="fenceHeight"] [class^="6foc"]',
You have to separate the different inputs with a comma as shown here:
$(document.body).on('keypress keydown keyup change', '[class^="footage"],[class^="fenceHeight"],[class^="6foc"]',
Second was this line:
var fenceHeight = $(":input[name='fenceHeight_" + fenceNumber + "'" + ']').val();
You're getting the value of the select, when really you want the value of the selected option:
var fenceHeight = $(":input[name='fenceHeight_" + fenceNumber + "'" + ']').find('option:selected').val();
Third was this line:
var railQuantity = $(":input[name='railQuantity_" + fenceNumber + "'" + ']').val();
You're getting the value of this line, when down in the code you're actually trying to set the value of the value. What you want is just the element. I've left the quantity in there in case you want that later, but repurposed railQuantity:
var railQuantity = $(":input[name='railQuantity_" + fenceNumber + "'" + ']');
var railQuantityval = $(":input[name='railQuantity_" + fenceNumber + "'" + ']').val();
Fourth is your if statement:
if (fenceHeight = !NaN) {
You can't really use it like that. Use this instead:
if (!isNaN(Number(fenceHeight))) {
Down in the if statement, you also could benefit from if/else statements instead of just if statements. I've changed those to reflect this.
You were also missing the railsQuantity element in your add function, which I added for you:
parts = $('.railQuantity:last').attr('name').split("_");
parts[1]++;
$('.railQuantity:last').attr('name', parts.join("_"));
Updated fiddle here.