I am doing an exercise to learn JavaScript. I am having issues making my program dynamic. What I want to do here is:
Create two input to let the user set up the new product data.
Create a button. This button will have assigned a click event that will: 1- Get the data from the inputs. 2- Create a new product row with the data we stored.
Be able to delete all items and decrease total price based on the price of reminding item. In case there is no item, total price should be 0.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Shoping</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="js/index.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<header>
<h1 class="h1 text-center mb">Shoping<span class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></span></h1>
</header>
<table class="table mb">
<thead>
<tr>
<th>Products:</th>
<th>Price:</th>
<th>Quantity:</th>
<th>Total:</th>
<th>
</th>
</tr>
</thead>
<tbody id="soyTBody">
<tr id="itemSubject">
<th scope="row"><span id="productName">T-Shirts</span></th>
<td class="price1"> <span class="dolar">$</span><span id="product">15</span></td>
<td class="qty1">
<form class="form-inline">
<div class="form-group">
<label for="inputQty">QTY</label>
<input type="text" id="qty" class="form-control mx-sm-3" maxlength="3" aria-describedby="qtyItem1">
</div>
</form>
</td>
<td <span class="dolar">$</span><span id="total">0.00</span></td>
<td class="text-right">
<button class="delate btn btn-danger" type="button" onclick="removeItem()" value="delate">
<input id ="delateButton" class="delateItem" type="button" value="Delate">
</button>
</td>
</tr>
<tr id="itemSubject2">
<th scope="row"><span id="productName">Stickers</span></th>
<td class="price2"> <span class="dolar">$</span><span id="product2">2</span></td>
<td class="qty2">
<form class="form-inline">
<div class="form-group">
<label for="inputQty">QTY</label>
<input type="text" id="qty2" class="form-control mx-sm-3" maxlength="3" aria-describedby="qtyItem2">
</div>
</form>
</td>
<td <span class="dolar">$</span><span id="total2">0.00</span></td>
<td class="text-right">
<button class="delate btn btn-danger" type="button" onclick="removeItem2()" value="delate">
<input id ="delateButton" class="delateItem" type="button" value="Delate">
</button>
</td>
</tr>
<!-- <tr>
<th scope="row">Stickers</th>
<td class="price2">$1</td>
<td class="qty2">
<form class="form-inline">
<div class="form-group">
<label for="inputPassword4">QTY</label>
<input type="text" id="qty2text" class="form-control mx-sm-3" aria-describedby="passwordHelpInline">
</div>
</form>
</td>
<td class="total-2">$0.00</td>
<td class="text-right">
<button class="delate btn btn-danger" type="button" value="delate">
<span class="delateButton"><strong>Delate</strong></span>
</button>
</td>
</tr> -->
<!-- <tr>
<th scope="row">Flags</th>
<td class="price3">$2</td>
<td class="qty3"><form class="form-inline">
<div class="form-group">
<label for="inputPassword4">QTY</label>
<input type="text" id="qty3text" class="form-control mx-sm-3" aria-describedby="passwordHelpInline">
</div>
</form>
</td>
<td class="total3">$0.00</td>
<td class="text-right">
<button class="delate btn btn-danger" type="button" value="delate">
<span class="delateButton"><strong>Delate</strong></span>
</button>
</td>
</tr> -->
</tbody>
</table>
<div class="row text-right">
<button class="delate btn btn-success" onclick="getPrice();getPrice2();totalPrice2()" type="submit" value="calculatePriceButton" >
<input id ="calc-prices-button" class="calculator" type="button" value="Calculate Prices">
<!-- <span class="delateButton"><strong>Calculate Prices</strong></span> -->
</button>
</div>
<h2 class="text-center">Total Price: $<span id="totalPrice"></span></h2>
</div>
</body>
</html>
JS:
// qty
function getQty() {
var qty = document.querySelector("#qty").value;
document.querySelector("#total").innerHTML = qty;
return qty;
}
getQty();
// qty2
function getQty2() {
var qty2 = document.querySelector("#qty2").value;
document.querySelector("#total2").innerHTML = qty2;
return qty2;
}
getQty();
// Price
function getPrice() {
var price = parseInt(document.querySelector("#product").innerHTML);
document.querySelector("#total").innerHTML = price * getQty();
}
getPrice();
// Price 2
function getPrice2() {
var price2 = parseInt(document.querySelector("#product2").innerHTML);
document.querySelector("#total2").innerHTML = price2 * getQty2();
}
getPrice2();
// total Price
function totalPrice2() {
var total = parseInt(document.querySelector("#total").innerHTML);
var total2 = parseInt(document.querySelector("#total2").innerHTML);
document.querySelector("#totalPrice").innerHTML = total + total2;
}
totalPrice2();
//Romove Item
function removeItem() {
var remove = document.querySelector("#itemSubject").remove("itemSubject");
// setTimeout(function() { alert("Your shopping cart is empty"); }, 1000);
}
removeItem();
function removeItem2() {
var remove = document.querySelector("#itemSubject2").remove("itemSubject2");
// setTimeout(function() { alert("Your shopping cart is empty"); }, 1000);
}
removeItem2();
For your getPrice() and getPrice2() functions, we can make them dynamic by changing the following:
var price = parseInt(document.querySelector("#product").innerHTML);
and
var price2 = parseInt(document.querySelector("#product2").innerHTML);
These lines looks for elements with static names, instead we should give all inputs a common class name and loop through them. That way, we don't have to rely on static element IDs. For example, if we gave each input the class 'quantityinput', we can do the following:
var elements = document.getElementsByClassName("quantityinput");
for(var i=0; i<elements.length; i++) {
// Select this element and get its quantity
var this_total = elements[i].value;
// Get the price for this element by selecting the price td, then its second child
var this_price = elements[i].parentElement.parentElement.parentElement.previousSibling.childNodes[2].value;
// Select the total label for this row
var this_total_label = elements[i].parentElement.parentElement.parentElement.childNodes[1];
// Now update the total label for this row by multiplying the price and the quantity
this_total_label.value = this_total * this_price;
}
Now we don't have to worry about a certain row missing, since we iterate through all existing rows. A similar approach can be taken when calculating the total price for all rows, just loop through each rows total price, add them together then assign the total to the total price label.
Related
I am creating form dynamically which has n rows (coming from array having n elements). Form fields have two type of columns (text & number) which I have given different id.
Although JQuery validation is working but "validate parts button" is not responding correctly. From the code condition it should not be enabled in case text is not valid.
Thanks..!
<div class="container-sm">
<div class="col-md-12 text-center">
<input class="btn btn-outline-primary" type="button" onclick = "buildTagPartsTable()" id="partNum" style="height:40px; width:220px" value="Enter Form Details#">
</div>
</div>
<div class="container-sm">
<div class="row">
<form id = "partsQuantForm">
<div class="col-lg-12" style="width:700px;overflow:auto; max-height:400px;">
<div class="partsTagsForm">
<table class="table table-striped" id="validTagsParts" style="width:100%;">
<thead>
<tr>
<th>Valid Row</th>
<th>Part </th>
<th># </th>
<th>Part </th>
<th># </th>
</tr>
</thead>
<tbody id="tagsPartsTable"></tbody>
</table>
</div>
<div class="col-md-12 text-center">
<input class="btn btn-outline-primary" type="button" id="tagsParts" style="height:40px; width:220px" value="Validate Parts ">
</div>
</div>
</form>
</div>
</div>
<script>
function buildTagPartsTable(){
validTagsInfo = ['Row1', 'Row2', 'Row3', 'Row4', 'Row5'];
var table = "<table>";
for (let key in validTagsInfo) {
table += `<tr>
<td>${validTagsInfo[key]}</td>
<td><input type="text" class="form-control" id = "partInfo" name="partInfo[0]" style="width:5em" minlength="5" maxlength="5" ></td>
<td><input type="number" class="form-control" id = "partQuantInfo" name="partQuantInfo[0]" style="width:3em" minlength="1" maxlength="1"></td>
<td><input type="text" class="form-control" id = "partInfo" name="partInfo[1]" style="width:5em" minlength="5" maxlength="5"></td>
<td><input type="number" class="form-control" id = "partQuantInfo" name="partQuantInfo[1]" style="width:3em" minlength="1" maxlength="1"></td>
</tr>`;
}
table += "</table>";
document.getElementById("tagsPartsTable").innerHTML = table;
}
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-validation#1.17.0/dist/jquery.validate.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
$(document).ready(function() {
$('input').on('blur', function() {
if ($("#partsQuantForm").valid()) {
$('#tagsParts').prop('disabled', false);
} else {
$('#tagsParts').prop('disabled', true);
}
});
jQuery("#partsQuantForm").validate({
rules: {
'partInfo[]': {
required: true,minlength: 5,maxlength: 5
},
'partQuantInfo[]': {
required: true,minlength: 2,maxlength: 2
}
}
});
});
</script>
I have found a lot of answers to this type of question but none are solving the problem.
I even have a very similar piece of code that works. However, this keeps giving a NaN. I have narrowed it down to not being able to get the value of
var or = parseFloat($(this).siblings("input[name='or']").val());
Here is what I have.
Any help is greatly appreciated!
<tbody>
{% for i in t %}
<tr class="hotlines">
<td><strong>{{i.owner}}</strong><br>{{i.owner_id}}</td>
<td>
<li>{{i.tot_itm}}</li>
<li>Per Piece Profit: {{"${:,.2f}".format(i.item_prof)}}</li>
</td>
<td>
<li>Payable Hotlines <br><input type="text" name="hln" maxlength="4" value=""></li>
<li>Per Hotline Profit: {{"${:,.2f}".format(i.hotline_prof)}}</li>
<input type="text" name="or" value="{{i.hotline_prof}}">
</td>
<td>
<li>Total Backpack Profit: {{"${:,.2f}".format(i.tot_prof)}}</li>
<li>Total Hotline Profit: <input type="text" name="hlnt" readonly /></li>
</td>
</tr>
<!-- Total items sent from db -->
<input class="hidden" type="text" name="it" value="{{i.tot_itm}}">
<!-- per hotline override from db -->
<!-- profit from all items * per item override sent from server -->
<input class="hidden" type="text" name="bp" value="{{i.tot_prof}}">
<!-- total proffit from items and hotlines -->
<input class="hidden" type="text" name="th">
<!-- per item override from db -->
<input class="hidden" type="text" name="or_it" value="{{i.item_prof}}">
<!-- total proffit from hotlines -->
<input class="hidden" type="text" name="hl" value="0">
<!-- organization ID -->
<input class="hidden" type="text" name="o" value="{{org.organization_ID}}">
<input class="hidden" type="text" name="owner_n" value="{{i.owner}}">
<input class="hidden" type="text" name="owner_id" value="{{i.id}}">
{% endfor %}
<td><button type="submit" class="btn btn-link btn-xs btn-block">Submit Report</button></td>
</tbody>
AND
$(document).on("keyup", "[name='hln']", function () {
$this = $(this);
//var or = 0
var pro = 0
//using native dom Element.closest() method
//https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
let parent = $(this.closest('.hotlines'));
//or using jQuery's closest();
//let parent = $this.closest('.hotlines');
var value = parseFloat($this.val());
var or = parseFloat($(this).siblings("input[name='or']").val());
var bp = parseFloat($(this).siblings("input[name='bp']").val());
//var other = parseFloat($(this).siblings("input[name='amt']").val());
pro = (value * or);
var total = (pro + bp);
//use find() to find the child element
parent.find('input[name="hlnt"]').val("$" + pro.toFixed(2));
parent.find('input[name="total"]').val("$" + total.toFixed(2));
parent.find('input[name="th"]').val(total);
parent.find('input[name="hl"]').val(pro);
});
With the guidance from Tyler Roper it was a simple fix having nothing to do with Javascript.
I was tired and testing things and tried to quickly convert a page into a table.
The terrible HTML was the cause. To fix it I simply changed to:
<form action="/weekly_reports/" method="POST">
<table id="office_weekly" class="table table-hover table-striped">
<thead>
<th>Office</th>
<th>Backpacks</th>
<th>Hotlines</th>
<th>Total</th>
</thead>
<tbody>
{% for i in t %}
<tr class="hotlines">
<td><strong>{{i.owner}}</strong><br>{{i.owner_id}}</td>
<td>
{{i.tot_itm}}<br>
Per Piece Profit: {{"${:,.2f}".format(i.item_prof)}}
</td>
<td>
Payable Hotlines <br><input type="text" name="hln" maxlength="4" value=""><br>
Per Hotline Profit: {{"${:,.2f}".format(i.hotline_prof)}}<br>
<input type="hidden" name="or" value="{{i.hotline_prof}}">
</td>
<td>
Total Backpack Profit: {{"${:,.2f}".format(i.tot_prof)}}
</td>
<td>Total Hotline Profit: <input type="text" name="hlnt" readonly /></td>
</tr>
{% endfor %}
<td><button type="submit" class="btn btn-link btn-xs btn-block">Submit Report</button></td>
</tbody>
</table>
</form>
found this solution in this solution
function commaSeparateNumber(val){
while (/(\d+)(\d{3})/.test(val.toString())){
val = val.toString().replace(/(\d+)(\d{3})/, '$1'+','+'$2');
}
return val;
}
in this link add commas to a number in jQuery
I am trying to apply it in my project. it works in one column but it doesn't work in price and sub total
function commaSeparateNumber(val){
while (/(\d+)(\d{3})/.test(val.toString())){
val = val.toString().replace(/(\d+)(\d{3})/, '$1'+','+'$2');
}
return val;
}
var rowCount = 1;
$('#add').click(function() {
rowCount++;
$('#orders').append('<tr id="row'+rowCount+'"><td><input class="form-control product_price" type="number" data-type="product_price" id="product_price_'+rowCount+'" name="product_price[]" for="'+rowCount+'"/></td><input class="form-control" type="hidden" data-type="product_id" id="product_id_'+rowCount+'" name="product_id[]" for="'+rowCount+'"/><td><input class="form-control quantity" type="number" class="quantity" id="quantity_'+rowCount+'" name="quantity[]" for="'+rowCount+'"/> </td><td><input class="form-control total_cost" type="text" id="total_cost_'+rowCount+'" name="total_cost[]" for="'+rowCount+'" readonly/> </td><td><button type="button" name="remove" id="'+rowCount+'" class="btn btn-danger btn_remove cicle">-</button></td></tr>');
});
// Add a generic event listener for any change on quantity or price classed inputs
$("#orders").on('input', 'input.quantity,input.product_price', function() {
getTotalCost($(this).attr("for"));
});
$(document).on('click', '.btn_remove', function() {
var button_id = $(this).attr('id');
$('#row'+button_id+'').remove();
});
// Using a new index rather than your global variable i
function getTotalCost(ind) {
var qty = $('#quantity_'+ind).val();
var price = $('#product_price_'+ind).val();
var totNumber = (qty * price);
var tot = totNumber.toFixed(2);
tot = commaSeparateNumber(totNumber);
$('#total_cost_'+ind).val(tot);
calculateSubTotal();
}
function calculateSubTotal() {
var subtotal = 0;
$('.total_cost').each(function() {
subtotal += parseFloat($(this).val());
});
$('#subtotal').val(commaSeparateNumber(subtotal));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</head>
<body>
<div class="col-md-12">
<div class="line line-dashed line-lg pull-in"></div>
<div class="row">
<table class="table table-bordered" id="orders">
<tr>
<th>Price</th>
<th>Quantity</th>
<th>Total Cost</th>
<th>
</th>
</tr>
<tr>
<td><input class="form-control product_price" type='number' data-type="product_price" id='product_price_1' name='product_price[]' for="1"/></td> <!-- purchase_cost -->
<td><input class="form-control quantity" type='number' id='quantity_1' name='quantity[]' for="1"/></td>
<td><input class="form-control total_cost" type='text' id='total_cost_1' name='total_cost[]' for='1' readonly/></td>
<td><button type="button" name="add" id="add" class="btn btn-success circle">+</button></td>
</tr>
</table>
<input class="form-control" type='hidden' data-type="product_id_1" id='product_id_1' name='product_id[]'/>
</div>
</div>
<div class="line line-dashed line-lg pull-in" style="clear: both;"></div>
<div class="col-md-12 nopadding">
<div class="col-md-4 col-md-offset-4 pull-right nopadding">
<div class="col-md-8 pull-right nopadding">
<div class="form-group">
<td><input class="form-control subtotal" type='text' id='subtotal' name='subtotal' readonly/></td>
</div>
</div>
<div class="col-md-3 pull-right">
<div class="form-group">
<label>Subtotal</label>
</div>
</div>
</div>
</div>
</body>
</html>
Thank you so much in advance!
The problem is that parseFloat fails to correctly parse the value from the total cost textbox because it contains one or more ,. You need to remove the , from the string before parsing to float. You can remove any ,'s by calling .replace(/,/g,'') on the textbox value in the calculateSubTotal function.
It seems that for some values the function commaSeparateNumber doesn't work as expected. I removed it from the snippet below and replaced it with toLocaleString() which takes parameters for locale and minimum/maximum fraction digits .toLocalString("en-US", { maximumFractionDigits: 2}). Set the locale to one you know uses , to separate thousands. If you know that won't be an issue you can pass undefined for the locale.
Your snippet has been updated below:
var rowCount = 1;
$('#add').click(function() {
rowCount++;
$('#orders').append('<tr id="row'+rowCount+'"><td><input class="form-control product_price" type="number" data-type="product_price" id="product_price_'+rowCount+'" name="product_price[]" for="'+rowCount+'"/></td><input class="form-control" type="hidden" data-type="product_id" id="product_id_'+rowCount+'" name="product_id[]" for="'+rowCount+'"/><td><input class="form-control quantity" type="number" class="quantity" id="quantity_'+rowCount+'" name="quantity[]" for="'+rowCount+'"/> </td><td><input class="form-control total_cost" type="text" id="total_cost_'+rowCount+'" name="total_cost[]" for="'+rowCount+'" readonly/> </td><td><button type="button" name="remove" id="'+rowCount+'" class="btn btn-danger btn_remove cicle">-</button></td></tr>');
});
// Add a generic event listener for any change on quantity or price classed inputs
$("#orders").on('input', 'input.quantity,input.product_price', function() {
getTotalCost($(this).attr("for"));
});
$(document).on('click', '.btn_remove', function() {
var button_id = $(this).attr('id');
$('#row'+button_id+'').remove();
});
// Using a new index rather than your global variable i
function getTotalCost(ind) {
var qty = $('#quantity_'+ind).val();
var price = $('#product_price_'+ind).val();
var totNumber = (qty * price);
// .toLocaleString
var tot = totNumber.toLocaleString("en-US", { maximumFractionDigits: 2});
$('#total_cost_'+ind).val(tot);
calculateSubTotal();
}
function calculateSubTotal() {
var subtotal = 0;
$('.total_cost').each(function() {
// replace ',' here
subtotal += parseFloat($(this).val().replace(/,/g,''));
});
// toLocaleString
$('#subtotal').val(subtotal.toLocaleString("en-US", { maximumFractionDigits: 2}));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</head>
<body>
<div class="col-md-12">
<div class="line line-dashed line-lg pull-in"></div>
<div class="row">
<table class="table table-bordered" id="orders">
<tr>
<th>Price</th>
<th>Quantity</th>
<th>Total Cost</th>
<th>
</th>
</tr>
<tr>
<td><input class="form-control product_price" type='number' data-type="product_price" id='product_price_1' name='product_price[]' for="1"/></td> <!-- purchase_cost -->
<td><input class="form-control quantity" type='number' id='quantity_1' name='quantity[]' for="1"/></td>
<td><input class="form-control total_cost" type='text' id='total_cost_1' name='total_cost[]' for='1' readonly/></td>
<td><button type="button" name="add" id="add" class="btn btn-success circle">+</button></td>
</tr>
</table>
<input class="form-control" type='hidden' data-type="product_id_1" id='product_id_1' name='product_id[]'/>
</div>
</div>
<div class="line line-dashed line-lg pull-in" style="clear: both;"></div>
<div class="col-md-12 nopadding">
<div class="col-md-4 col-md-offset-4 pull-right nopadding">
<div class="col-md-8 pull-right nopadding">
<div class="form-group">
<td><input class="form-control subtotal" type='text' id='subtotal' name='subtotal' readonly/></td>
</div>
</div>
<div class="col-md-3 pull-right">
<div class="form-group">
<label>Subtotal</label>
</div>
</div>
</div>
</div>
</body>
</html>
I used JavaScript to clone and add rows. How can separate validation be done for each row?
var i = 0;
function cloneRow() {
var row = document.getElementById("clone");
var table = document.getElementById("data");
var selectIndex = 1;
var clone = row.cloneNode(true);
table.appendChild(clone);
clone.setAttribute("style", "");
}
function deleteRow(btn) {
var result = confirm("Do you Want to delete this ?");
if (result) {
var row = btn.parentNode.parentNode;
row.parentNode.removeChild(row);
}
}
<div class="row">
<div class="col-sm-12">
<div class="col-sm-7"></div>
<div class="col-sm-2">
<button type="button"class="btn btn-primary default btn-xs" onclick="cloneRow()" >add more...</button>
</div>
</div>
</div><br><br>
<div class="row" id ="close">
<div class="col-sm-4"></div>
<div class='col-sm-4'>
<form id="NAME_VALUE" method="POST">
<table class="table-striped">
<tbody id="data">
<tr id ="clone" style="display:none;">
<td>
Name :<input type="text" name="INPUT_NAME" style="width:100px;" id="name" name="INPUT_NAME">
</td>
<td>
Value :<input type="text" name="INPUT_VALUE" style="width:100px;" id="value" name="INPUT_VALUE">
</td>
<td>
<button type="button"class="btn btn-primary default btn-xs" name ="delete" style="margin-left: 5px;" onclick="deleteRow(this); return false;">
<span class="glyphicon glyphicon-remove-circle" style="text-align:center" ></span>
</button>
</td>
</tr>
<tr>
<td>
Name :<input type="text" name="INPUT_NAME" style="width:100px;" id="name" name="INPUT_NAME">
</td>
<td>
Value :<input type="text" name="INPUT_VALUE" style="width:100px;" id="value" name="INPUT_VALUE">
</td>
<td>
<button type="button"class="btn btn-primary default btn-xs" name ="delete" style="margin-left: 5px;" onclick="deleteRow(this); return false;">
<span class="glyphicon glyphicon-remove-circle" style="text-align:center" ></span>
</button>
</td>
</tr>
</tbody>
</table><br>
<button type="button"class="btn btn-primary default btn-xs" style="margin-left: 5px;" onclick="submit_login(); return false;"> save.</button>
</form>
</div>
</div>
I'd like to create this type of validation for every row or <tr>.
When the add button is clicked a new input is dynamically added. However when the form is submitted only the first input field is validated. How can I validate the dynamically added inputs?
If you want to separate the validation for each row - you should create a row constructor.
Basically when you clone a new row - you clone the constructor with all its methods inside.
var Row = function () {
this.name = "";
this.value = "";
//add more properties
}
Create the methods:
Row.prototype.verify = function () {
return this.name !== `undefined` && this.value !== `undefined`;
}
In your clone function you just have to call it:
var rowInstance = new Row();
And you can use it like that:
if (rowInstance.verify()) {
//if the row information is valid then do something
}
I am creating a dynamic form list and in row there is a subtotal value and what I need is to have a grand total. But my problem is I can't sum all the values.
Here's a bit of my code:
//i created a array that will hold all subtotals
$scope.grand_total = [];
//this function is visible in every row
$scope.subTotal = function($index) {
var total = 0;
angular.forEach($scope.quoteHeader.items[$index], function(value){
angular.forEach(value.items, function(v) {
total += v.unit * v.unit_price;
$scope.grand_total.push({
subtotal: total
});
});
});
return total;
}
//this will process the sum but It didn't work
function computeGrandTotal() {
var total = 0;
angular.forEach($scope.grand_total, function(value) {
console.log(value);
});
}
$scope.grandTotal = function() {
var total = 0.00;
computeGrandTotal(); //call the subtotal function
console.log(computeGrandTotal());
return total;
}
Here's the plnkr: http://plnkr.co/edit/Bfd1e5?p=preview
I hope you can help me with this. Thats all thanks :)
You need to store the total at the given index in the sub_total array then
var quotationList = angular.module('quotation_list', []);
quotationList.controller('quoteList', function($scope) {
$scope.quoteHeader = {};
$scope.quoteHeader = {
items: []
}
$scope.json_output = angular.fromJson($scope.quoteHeader); //display json view
$scope.addParticularHeader = function() {
$scope.quoteHeader.items.push({
particular_name: 'SAMPLE PARTICULAR TITLE',
child_label: {
items: []
}
});
}
$scope.removeQuoteHeader = function($index) {
$scope.quoteHeader.items.splice($index, 1);
}
$scope.addParent = function($index) {
//here we will append the new row
//console.log($scope.quoteHeader.items[$index].child_label);
$scope.quoteHeader.items[$index].child_label.items.push({
particular: 'Sample Particular Name',
unit: 1,
unit_label: 'sqm',
unit_price: 0.00,
unit_subtotal: 0.00,
sublevel: {
items: []
}
});
}
$scope.removeParent = function(parent_id, $index) {
$scope.quoteHeader.items[parent_id].child_label.items.splice($index, 1);
}
$scope.addSubLevel = function(parent_id) {
console.log(parent_id);
}
$scope.grand_total = [];
$scope.subTotal = function($index) {
var total = 0;
angular.forEach($scope.quoteHeader.items[$index], function(value) {
angular.forEach(value.items, function(v) {
total += v.unit * v.unit_price;
});
});
$scope.grand_total[$index] = total;
return total;
}
function computeGrandTotal() {
var total = 0;
//console.log($scope.grand_total);
angular.forEach($scope.grand_total, function(value) {
console.log('total', value);
total += value;
});
return total;
}
$scope.grandTotal = function() {
return computeGrandTotal();
}
});
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="//code.angularjs.org/1.3.16/angular.js"></script>
<div class="container">
<h1>Quotation List</h1>
<div ng-app="quotation_list" class="row">
<div ng-controller="quoteList">
<div class="row">
<div class="col-md-12 text-right">
<button ng-click="addParticularHeader()" class="btn btn-primary" type="button">
<span class="fa fa-plus"></span>
Add Particular Header</button>
</div>
</div>
<hr />
<div class="row" ng-repeat="item in quoteHeader.items">
<div class="panel panel-default">
<div class="panel-heading">
<h5 contenteditable="" class="panel-title">{{ item.particular_name }} - {{ $index + 1}} <span ng-click="removeQuoteHeader($index)" class="pull-right btn btn-danger">
<span class="fa fa-times"></span>
Remove</span>
</h5>
<div class="clearfix"></div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<td class="text-center">No.</td>
<td class="text-center">Particulars</td>
<td class="text-center">Unit</td>
<td class="text-center">Unit Label</td>
<td class="text-center">Unit(Price)</td>
<td class="text-center">Unit Price(Php)</td>
<td class="text-center"></td>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in quoteHeader.items[$index].child_label.items">
<td class="text-center">{{ $index + 1 }}</td>
<td class="text-center">
<input type="text" ng-model="item.particular" class="form-control" />
</td>
<td class="text-center">
<input type="number" ng-minlength="1" ng-model="item.unit" class="form-control text-center" />
</td>
<td class="text-center">
<select class="form-control">
<option value="sqm">sqm</option>
<option value="lot">lot</option>
<option value="sets">sets</option>
</select>
</td>
<td class="text-center">
<input type="number" ng-model="item.unit_price" class="form-control text-right" />
</td>
<td class="text-center">
<input type="text" readonly="" value="{{ item.unit * item.unit_price | currency: '₱ ' }}" class="form-control text-right" />
</td>
<td class="text-center">
<button ng-click="addSubLevel($parent.$index)" class="btn btn-primary" type="button">
<span class="fa fa-plus"></span>
</button>
<button ng-click="removeParent($parent.$index, $index)" class="btn btn-danger" type="button">
<span class="fa fa-times"></span>
</button>
</td>
</tr>
<tr>
<td ng-show="!quoteHeader.items[$index].child_label.items.length" class="text-center" colspan="7">
<p>No list yet!</p>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="text-center" colspan="6">
<button ng-click="addParent($index)" class="btn btn-primary" type="button">
<span class="fa fa-plus"></span>Add Parent</button>
</td>
<td>
<label>Subtotal: <span>{{ subTotal($index) | currency: '₱ ' }}</span>
</label>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
<div ng-show="!quoteHeader.items.length" class="row text-center">
<p>No particulars yet!</p>
</div>
<div class="pull-right">
<label>Grand Total:</label>
<p>{{ grandTotal() }}</p>
<!--
<input type="text" class="form-control text-right" value="{{ grandTotal() | currency: '₱ ' }}" readonly />
-->
</div>
<div class="clearfix"></div>
</div>
</div>
</div>