store input value which is in loop with javascript - javascript

I have a column input field in <td> which is in the loop due to this each Row has input field I got a javascript from which it storing local storage for input field but the issue is this javascript is working only for one input For Example :
I have five rows and due to loop input field generated for 5 rows automatically
What I am looking for is to store different values for each row..due to this script its not implementing for each row individually
Code
<input type="text" id="txt_1" onkeyup='saveValue(this);'/>
Javascript
<script type="text/javascript">
document.getElementById("txt_1").value = getSavedValue("txt_1"); // set the value to this input
document.getElementById("txt_2").value = getSavedValue("txt_2"); // set the value to this input
/* Here you can add more inputs to set value. if it's saved */
//Save the value function - save it to localStorage as (ID, VALUE)
function saveValue(e){
var id = e.id; // get the sender's id to save it .
var val = e.value; // get the value.
localStorage.setItem(id, val);// Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue (v){
if (!localStorage.getItem(v)) {
return "";// You can change this to your defualt value.
}
return localStorage.getItem(v);
}
</script>
Image Showing
COde
<table class="table table-hover table-striped table-bordered" id="input-group">
<thead ><tr >
<th class="text-right"><?php echo "Contact No."; ?></th>
<th><?php echo "Followup 1 Date"; ?>
</th></tr></thead>
<tbody>
<?php
if (empty($enquiry_list)) {
?>
<?php
} else {
foreach ($enquiry_list as $key => $value) {
$current_date = date("d/m/Y");
$next_date = $value["next_date"];
if (empty($next_date)) { $next_date = $value["follow_up_date"];
}if ($next_date < $current_date) {
$class = "class='danger'";} else {
$class = ""; } ?>
<td class="mailbox-name"><?php echo $value['contact']; ?> </td>
<td class="mailbox-name" >
<div style="width:200px" style="height:200px" >
<input id="txt_<?= $row[id] ?>" onkeyup='saveValue(this);'
autocomplete="off" type="text" class="form-control" /></div></td>
</tr> </tr>
<?php }}?> </tbody> </table>

var inputGroup = document.getElementById('input-group');
var inputs = inputGroup.getElementsByTagName('input');
for(i=0;i<inputs.length;i++)
{
var id = inputs[i].getAttribute('id');
inputs[i].value = getSavedValue(id);
}
//Save the value function - save it to localStorage as (ID, VALUE)
function saveValue(e){
var id = e.id; // get the sender's id to save it .
var val = e.value; // get the value.
localStorage.setItem(id, val);// Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue (v){
if (!localStorage.getItem(v)) {
return "";// You can change this to your defualt value.
}
return localStorage.getItem(v);
}
<table id="input-group">
<tr>
<th>Text 1</th>
<th><input type="text" id="txt_1" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 2</th>
<th><input type="text" id="txt_2" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 3</th>
<th><input type="text" id="txt_3" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 4</th>
<th><input type="text" id="txt_4" onkeyup='saveValue(this);'/> </th>
</tr>
<tr>
<th>Text 5</th>
<th><input type="text" id="txt_5" onkeyup='saveValue(this);'/> </th>
</tr>
</table>

First of all you need to pass the event listener to the function that you have implemented, so i've solved it adding the events on the js file.
So instead of this:
<input type="text" id="txt_1" onkeyup='saveValue(this);'/>
You need to add the event on the js:
<input type="text" id="txt_1"/>
<input type="text" id="txt_2"/>
document.getElementById("txt_1").onkeyup = saveValue;
document.getElementById("txt_2").onkeyup = saveValue;
After this you need to access the id and the value from the event.target like this:
function saveValue(e) {
var id = e.target.id; // get the sender's id to save it .
var val = e.target.value; // get the value.
localStorage.setItem(id, val); // Every time user writing something, the localStorage's value will override .
}
Look at this codesandbox and see if it helps you out

Html is not reliable. You can use pure javascript code for cleaner way. Here is the working sample. Slackblitz https://stackblitz.com/edit/js-xycijp
function saveValue({ target }, index) {
localStorage.setItem(target.id, target.value); // Every time user writing
// OR
localStorage.setItem("target.id"+index, target.value); // Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue(v) {
if (!localStorage.getItem(v)) {
return ""; // You can change this to your defualt value.
}
return localStorage.getItem(v);
}
document.querySelectorAll(".textField").forEach((elm, index) => {
elm.addEventListener("input", (e) => saveValue(e, index), false);
});
// Can ignore
window.saveValue = saveValue;
window.getSavedValue = getSavedValue;
<input class='textField' type="text" id="txt_1" />
<input class='textField' type="text" id="txt_2" />

Related

Javascript Uncaught TypeError: value.toUpperCase is not a function

I am trying to use the following script to let the user filter the rows in a table based on the value they type. They can update that row, after the update event happend the page gets refreshed/relouded and the page shows all rows again. I am trying to find a way to keep the rows they filtered after the refresh/reload occrured. In other words as if the refresh never happend.
I get the following error: Uncaught TypeError: value.toUpperCase is not a function
at filterTable (accounts.php:1270)
at HTMLInputElement.<anonymous> (accounts.php:1291)
at HTMLInputElement.<anonymous>
This is the code;
<table class="userprof" align='left'>
<tr>
<td class="footer">Filter:
<input type="text" id="myInput" name="filter" style="color:black !important;" placeholder="Filter table" />
</td>
</tr>
</table>
</p><br /><br /><br />
</head>
<table width="99%" id="myTable" class="sortable" >
<tr>
<td class="header" style="padding: 1px;">Name</td>
<td class="header">Email</td></tr>
<? //Selecteer accounts.
$stmt = $mysqli->prepare("SELECT * FROM account WHERE purpose= ?");
$stmt->bind_param("s", $status);
$stmt->execute();
$result = $stmt->get_result();
}
while ($row = $result->fetch_assoc()) {
<td style="color:<?= htmlspecialchars($cat_color) ?> ", class="footer"><?= htmlspecialchars($row['name']) ?></td>
<td style="color:<?= htmlspecialchars($cat_color) ?> ", class="footer"><?= htmlspecialchars($row['email']) ?></td>
<td class="footer" width="1px"><input type="button" value="Edit" id="<?php echo htmlspecialchars($row['id']); ?>" onClick="this.style.color='gold';"
class="submit edit_data" /></td>
</form>
</tr>
<? } ?>
</table><div id="bottom"></div>
<script type="text/javascript">
// Store the input in a variable for reference.
var myInput = document.getElementById("myInput");
var savedValue = getSavedValue("myInput");
// Immediately filter the table and set the input value.
filterTable(savedValue);
myInput.value = savedValue;
//Save the value function - save it to localStorage as (ID, VALUE)
function saveValue(e) {
var id = e.id; // get the sender's id to save it .
var val = e.value; // get the value.
localStorage.setItem(id, val); // Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue(v) {
if (!localStorage.getItem(v)) {
return ""; // You can change this to your default value.
}
return localStorage.getItem(v);
}
function filterTable(value) {
console.log(value);
var filter = value.toUpperCase();
var rows = document.querySelector("#myTable tbody").rows;
for (var i = 0; i < rows.length; i++) {
var nameCol = rows[i].cells[1].textContent.toUpperCase();
var rankCol = rows[i].cells[2].textContent.toUpperCase();
var rankerCol = rows[i].cells[5].textContent.toUpperCase();
var typeCol = rows[i].cells[6].textContent.toUpperCase();
var emailCol = rows[i].cells[3].textContent.toUpperCase();
if (nameCol.indexOf(filter) > -1 || rankCol.indexOf(filter) > -1 || rankerCol.indexOf(filter) > -1 || typeCol.indexOf(filter) > -1 || emailCol.indexOf(filter) > -1) {
rows[i].style.display = "";
} else {
rows[i].style.display = "none";
}
}
}
myInput.addEventListener('keyup', function(event) {
console.log(event); // Check if the event is fired.
var value = event.target;
saveValue(event);
filterTable(value);
});
</script>
myInput.addEventListener('keyup', function(event) {
console.log(event); // Check if the event is fired.
var value = event.target.value;
saveValue(event);
filterTable(value);
});
It should be event.target.value. You missed the value property

How to make the Value in the inputText dynamic?

I m trying to make the default value for the input field from an array in the state..i could
put the values but after that i am not able to change the field any more ( it works wrong i can add only one letter which is strange )
(PS: there is only one input in my code ) :
when i change the value="" in the input it works but i need this table to contain the values from the state.
state ={
splitAmount : [ {
SplitAmount0: this.props.data.amount1
},
{
SplitAmount1: this.props.data.amount2
},
{
SplitAmount2: this.props.data.amount3
}
],
}
}
StopTyping = (event) => {
const self = this;
if (self.state.typingTimeout) {
clearTimeout(self.state.typingTimeout);
}
self.setState({
val : event.target.value,
name : event.target.name,
id : event.target.id,
typingTimeout: setTimeout(function () {
self.setAmount(self.state.name,self.state.id,self.state.val);
}, 1000)
});
}
setAmount=(name,id,val)=>{
this.removeSplitAmount(name);
let some=0;
for(var i=0;i<this.state.splitAmount.length;i++){
let splitAmountState=`SplitAmount${i}`;
some+=this.state.splitAmount[i][splitAmountState]
}
let newAmount=this.props.data.amount-(some+val);
if(some>0){
let newValues=[{[val]:val},{[`SplitAmount${id+1}`]:newAmount}]
let newSplitAmount=this.state.splitAmount.concat(newValues);
this.setState({splitAmount:newSplitAmount})
}
}
return(
<div>
{this.state.splitAmount.map((splitAmount,i)=>{
const splitAmountKey=i
return(
<table className="middle-table"key={i}>
<tbody>
<tr>
<th>DueDate</th>
<th>Status</th>
<th>Amount</th>
<th>VAT</th>
<th>Otherexpenses</th>
<th>SocialSecurity</th>
<th>Miscelaneous</th>
<th>TaxableAmount</th>
</tr>
<tr style={{height:40}}>
<td className="middle-table-
col">05.12.2018</td>
<td className="middle-table-colright-align">
{this.props.data.status}</td>
<td className="middle-table-colright-align">
<input className="tax-value" value=
{this.state.splitAmount[i][`SplitAmount ${i}`]} id={i} name=
{'SplitAmount'+i}
onChange=
{this.StopTyping}/>
</td>
<td className="middle-table-colright-align">
{this.props.data.vatAmount}</td>
<td className="middle-table-colright-align">
{this.props.data.otherExpenses}</td>
<td className="middle-table-colright-align">
{this.props.data.socialSecurityAmountIncluded}</td>
<td className="middle-table-colright-align">
{this.props.data.miscellaneousDeduction}</td>
<td className="middle-table-colright-
align"style={{backgroundColor:'#F4F6F8'}}>1000</td>
</tr>
</tbody>
</table>
)
})}
If you update state, never use the current state array or object: we always have to create a new structure and update the state with that. So, in your 'StopTyping' method (which should be renamed to 'taxValueChangeHandler', really!), say:
let newSplitAmount=[...this.state.splitAmount].concat(newValues);
It creates a new array with all values of splitAmount and concatenates that with the new values.
Then, in the input element, I'd always explicitly pass the event, if the event is needed in the method:
onChange={(e) => StopTyping(e)}
Hope this already helps!

JavaScript not updating value from HTML

I have a small problem. This is my HTML code fragment:
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr th:each="boiler : ${boilers}">
<td th:text="${boiler.value[0].model}"></td>
<td th:text="${boiler.value[0].brand}">
<td th:text="${#lists.size(boiler.value)}"></td>
<td th:text="${boiler.value[0].price}"></td>
<td>
<form>
<input type="text" th:class="boiler_model" th:id="boiler_model"
th:value="${boiler.value[0].model}" style="width:75px;"/>
<input class="form-control" type="number" id="quantity" style="width: 80px"/>
</form>
<td>
<button type="submit" class="btn btn-primary btn_submit" th:text="Add">Add</button>
</td>
</tr>
</tbody>
</table>
this is my jQuery:
$(document).ready(function () {
$('.btn_submit').on("click", function (e) {
e.preventDefault();
var quantity = $("#quantity").val();
// var boilerModel = $(".boiler_model").val();
var boilerModel = document.getElementById('boiler_model').value;
if (quantity === 0) {
alert("You must fill the quantity");
}
else if ($.trim(boilerModel) === "") {
alert("You must choose the model");
}
else {
var productIds = [];
$.ajax({
type: "POST",
url: "/order",
data: {quantity: quantity, model: boilerModel},
success: function (data) {
window.reload();
}
});
}
});
My problem is when I click the button it does read the quantity, but only reads the first model, even though it is printed in input correctly. I even removed the "hidden" type so I could see it for myself.
As you can see - the input is printed correctly, but when I debug this the controller always receives a quantity that is null if clicked on 2nd or 3rd model, but correct for the first one and model that is always the same. It always is "Super Hot Premium".
Could you please help me modify the table so it reads input separately from each row and then sends it to my controller?
Thank you very much.
There are several issues with your code :
you are looping through your boilers collection and generating a row for each loop. Each row contains two input fields with the same ids : quantity and boiler_model
in your click event handler, you are not looping through each row to submit data.
To fix this :
Follow this example to keep track of your loop status
Use the row index to generate unique ids for both your input fields
Store the size of your boilers collection in some hidden field to be able to send data from all rows
In your event handler, retrieve the size of your boilers collection and retrieve/send data for each row.
Here is a suggestion for your template (please note that I haven't tested it) :
<tr th:each="boiler, iterStatus : ${boilers}">
<td th:text="${boiler.value[0].model}"></td>
<td th:text="${boiler.value[0].brand}">
<td th:text="${#lists.size(boiler.value)}"></td>
<td th:text="${boiler.value[0].price}"></td>
<td>
<form>
<input type="text" th:class="boiler_model" id="boiler_model_${iterStatus.index}"
th:value="${boiler.value[0].model}" style="width:75px;"/>
<input class="form-control" type="number" id="quantity_${iterStatus.index}" style="width: 80px"/>
</form>
<td>
<button type="submit" class="btn btn-primary btn_submit" th:text="Add">Add</button>
</td>
</tr>
<input type="hidden" id="boilersLength" th:value="${#lists.size(boilers)}"/>
And your event handler :
$(document).ready(function () {
$('.btn_submit').on("click", function (e) {
var quantity, boilerModel, boilersLength, i;
e.preventDefault();
// retrieving the length of the boilers collection
boilersLength = $("#boilersLength").val();
// looping and sending data for each row :
for (i=0;i<boilersLength;i++) {
// retrieving data from both inputs :
quantity = $("#quantity_" + i).val();
boilerModel = $("#boiler_model_" + i).val();
if (quantity === 0) {
alert("You must fill the quantity");
}
else if ($.trim(boilerModel) === "") {
alert("You must choose the model");
}
else {
var productIds = [];
$.ajax({
type: "POST",
url: "/order",
data: {quantity: quantity, model: boilerModel},
success: function (data) {
// I wouldn't reload the window here, or you may reload before all data is sent
// window.reload();
}
});
}
}
});
}
You need to send a unique-id to identify on which Row the button is clicked so that you could get those values on your controller on the basis of that 'unique-id'
For Example :--
<tr th:each="boiler : ${boilers}">
<td th:text="${boiler.uniqueID}"></td>
<td th:text="${boiler.value[0].model}"></td>
<td th:text="${boiler.value[0].brand}">
<td th:text="${#lists.size(boiler.value)}"></td>
<td th:text="${boiler.value[0].price}"></td>
//Rest of your Code
<td>
<button type="submit" th:onclick="'javascript:addFunction(\'' + ${boiler.uniqueID} +'\');'" >Add</button>
</td>
</tr>

Insert corresponding data into dynamically added rows using "this"

I am newbie to Angular js.'this' operator will be helpful, but no idea how to use it.
On Each First Column, user will input the data, and corresponding that data should be fetched. Now data is fetched from php to Angular js, but how to push the data from angular js to that text box using "this" operator.
For eg: If 'Y' is entered then, X and Z should be push to textbox
If 'Q' is entered then, P and R should be push to textbox.
HTML:
<tr>
<td><input type="text" ng-model="bot.Wo_Id" /></td>
<td><input type="text" ng-click="acc1()" ng-value="b_code" /</td>
<td><input type="text" ng-value="Pre_req" /></td>
<td><a href ng-click="remove_bottle(bottle)">Remove</a></td>
</tr>
<tr>
<td><a href ng-click="add_bottle()">Add</a></td>
</tr>
Angular Js:
$scope.acc1 = function () {
$http.get("machin.php", {
params: {
"W_id": this.bot.Wo_Id,
"MC": "Machine"
}
})
.success(function (response) {
var values = response.split("#");
$scope.b_code = ?
$scope.Pre_req = ? // what should be code here
});
};
machin.php
echo X."#".Z //for input Y
echo P."#".R //for input Q
I am unable to sort this problem.Please help me.Thanks in advance.
This should do the trick:
Don't use this, use $scope.
Change ng-value to ng-model
HTML
<tr>
<td><input type="text" ng-model="bot.Wo_Id" /></td>
<td><input type="text" ng-click="acc1()" ng-model="b_code" /</td>
<td><input type="text" ng-model="Pre_req" /></td>
<td><a href ng-click="remove_bottle(bottle)">Remove</a></td>
</tr>
<tr>
<td><a href ng-click="add_bottle()">Add</a></td>
</tr>
Angular:
$scope.acc1 = function () {
$http.get("machin.php", {
params: {
"W_id": $scope.bot.Wo_Id,
"MC": "Machine"
}
})
.success(function (response) {
var values = response.split("#");
$scope.b_code = values[0];
$scope.Pre_req = values[1];
});
};
Here's a plunker with example. I can't do the http request so I just resolve the promise.
https://plnkr.co/edit/f6EzxBlaFInJghNwsXaU?p=preview

Error in updating field with dynamically generated row

I have inventory form to submit inventories to database. I'm facing an issue in updating unit cost and total cost of dynamically generated rows. As you can see in snapshots below. The name of products are fetching via autocomplete jQuery.
HTML CODE
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>Product Name/Code</th>
<th>Quantity</th>
<th>Unit Cost</th>
<th>Total Cost</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="p_scents">
<tr>
<td>1</td>
<td><input id="product_id" type="text" name="product_id[]" hidden><input id="product_code" type="text" name="product_code[]" hidden><input class="product_name form-control" id="product_name" type="text" placeholder="Type product name/code here" name="products[]" required></td>
<td><input class="quantity form-control" id="quantity" type="text" placeholder="Quantity to Buy" name="quantity[]" required /></td>
<td><div class="input-group"><span class="input-group-addon">$</span><input class="cost form-control" id="cost" placeholder="Unit Cost" type="text" readonly /></div></td>
<td><div class="input-group"><span class="input-group-addon">$</span><input class="total form-control" id="total" placeholder="Total" type="text" readonly /></div></td>
<td><button class="btn btn-default" type="button" id="addScnt"><i class="fa fa-plus "></i> Item</button></td>
</tr>
</tbody>
</table>
jQuery CODE
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type='text/javascript'>
jQuery(document).ready(function(){
var scntDiv = $('#p_scents');
var i = $('#p_scents tr').size() + 1;
$('#addScnt').click(function() {
scntDiv.append('<tr>'+
'<td>'+i+'</td>'+
'<td><input id="product_id" type="text" name="product_id[]" hidden><input id="product_code" type="text" name="product_code[]" hidden><input class="product_name form-control" id="product_name" type="text" placeholder="Type product name/code here" name="products[]" required></td>'+
'<td><input class="quantity form-control" id="quantity" type="text" placeholder="Quantity to Buy" name="quantity[]" required /></td>'+
'<td><div class="input-group"><span class="input-group-addon">$</span><input class="cost form-control" id="cost" placeholder="Unit Cost" type="text" readonly /></div></td>'+
'<td><div class="input-group"><span class="input-group-addon">$</span><input class="total form-control" id="total" placeholder="Total" type="text" readonly /></div></td>'+
'<td><a id="remScnt" class="btn btn-danger btn-xs"><span title="Delete" class="glyphicon glyphicon-remove"></span></a></td>'+
'</tr>');
i++;
//return false;
$('.product_name').autocomplete({
source:'http://localhost/Multi-Channel_Shipping/inc/auto_product.php',
minLength:2,
select:function(evt, ui)
{
// when a product is selected, populate related fields in this form
this.form.cost.value = ui.item.cost;
this.form.product_id.value = ui.item.product_id;
this.form.product_code.value = ui.item.product_code;
}
});
$('.quantity').keyup(function() {
updateTotal();
});
$('.cost').keyup(function() {
updateTotal();
});
var updateTotal = function () {
var input1 = parseFloat($('.quantity').val());
var input2 = parseFloat($('.cost').val());
if (isNaN(input1) || isNaN(input2)) {
if(!input2){
$('.total').val($('.quantity').val());
}
if(!input1){
$('.total').val($('.cost').val());
}
} else {
$('.total').val(input1 * input2);
}
};
var output_total = $('.total');
var total = input1 + input2;
output_total.val(total);
});
//Remove button
$(document).on('click', '#remScnt', function() {
if (i > 2) {
$(this).closest('tr').remove();
i--;
}
return false;
});
$('.product_name').autocomplete({
source:'http://localhost/Multi-Channel_Shipping/inc/auto_product.php',
minLength:2,
select:function(evt, ui)
{
// when a zipcode is selected, populate related fields in this form
this.form.cost.value = ui.item.cost;
this.form.product_id.value = ui.item.product_id;
this.form.product_code.value = ui.item.product_code;
}
});
$('.quantity').keyup(function() {
updateTotal();
});
$('.cost').keyup(function() {
updateTotal();
});
var updateTotal = function () {
var input1 = parseFloat($('.quantity').val());
var input2 = parseFloat($('.cost').val());
if (isNaN(input1) || isNaN(input2)) {
if(!input2){
$('.total').val($('.quantity').val());
}
if(!input1){
$('.total').val($('.cost').val());
}
} else {
$('.total').val(input1 * input2);
}
};
var output_total = $('.total');
var total = input1 + input2;
output_total.val(total);
});
</script>
AUTO_PRODUCT.PHP CODE
<?php
class DB
{
const DATABASE = 'multi-channel_shipping';
const HOST = 'localhost';
const USERNAME = 'root';
const PASSWORD = '';
static private $pdo;
static public function singleton()
{
if (!is_object(self::$pdo))
{
self::$pdo = new PDO('mysql:dbname=' . self::DATABASE . ';host=' . self::HOST,
self::USERNAME,
self::PASSWORD);
}
return self::$pdo;
}
private function __construct()
{
}
public function __clone()
{
throw new Exception('You may not clone the DB instance');
}
}
if (!isset($_REQUEST['term']))
{
die('([])');
}
$st = DB::singleton()
->prepare(
'SELECT * ' .
'FROM products ' .
'WHERE (name LIKE :name) OR (code LIKE :name) ' .
'ORDER BY name ASC ' .
'LIMIT 0,10');
$searchProduct = '%'.$_REQUEST['term'].'%';
$st->bindParam(':name', $searchProduct, PDO::PARAM_STR);
$data = array();
if ($st->execute())
{
while ($row = $st->fetch(PDO::FETCH_OBJ))
{
$data[] = array(
'value' => $row->code." - ".$row->name,
'cost' => $row->cost,
'product_id' => $row->id,
'product_code' => $row->code
);
}
}
echo json_encode($data);
flush();
?>
MySQL Data
--
-- Table structure for table `products`
--
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(100) NOT NULL,
`name` varchar(255) NOT NULL,
`unit` varchar(50) DEFAULT NULL,
`cost` decimal(25,2) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `code` (`code`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `products`
--
INSERT INTO `products` (`id`, `code`, `name`, `unit`, `cost`) VALUES
(1, '4815162342', 'BAZIC 12 Dil Dil Pak', 'Packet', '0.10'),
(2, '23', 'Razer', 'Piece', '0.03');
I also need to put shipping cost input field and show grand total of invoice at bottom of table.
There a multiple issues with the page & code, so I will try to cover what I can. #Barmar also spotted additional issues so will try to cover everything and suggest some improvements.
JSFiddle: http://jsfiddle.net/TrueBlueAussie/vx15mr4n/29/
Templating:
Rather than use text strings in code, it is easier to maintain HTML as HTML. The example I have provided uses a dummy script block (of type="text/template", which will be ignored by all browsers) but you can access the HTML content with $('#template').html().
Duplicate ID are invalid
You can't have duplicate IDs in a page. That is invalid HTML and jQuery will only see the first match. Use classes on the added elements instead and match on those.
so use:
<a class="remScnt"
and
$(document).on('click', '.remScnt', function()
Note: you will need to sort out any other duplicate IDs too (like product_id and quantity and cost and total). Your code already uses classes for those, so just move/delete the id attributes.
e.g. use classes for everything:
scntDiv.append('<tr>'+
'<td>'+i+'</td>'+
'<td><input class="product_id" type="text" name="product_id[]" hidden><input id="product_code" type="text" name="product_code[]" hidden><input class="product_name form-control" type="text" placeholder="Type product name/code here" name="products[]" required></td>'+
'<td><input class="quantity form-control" type="text" placeholder="Quantity to Buy" name="quantity[]" required /></td>'+
'<td><div class="input-group"><span class="input-group-addon">$</span><input class="cost form-control" placeholder="Unit Cost" type="text" readonly /></div></td>'+
'<td><div class="input-group"><span class="input-group-addon">$</span><input class="total form-control" placeholder="Total" type="text" readonly /></div></td>'+
'<td><a class="remScnt btn btn-danger btn-xs"><span title="Delete" class="glyphicon glyphicon-remove"></span></a></td>'+
'</tr>');
You are using a delegated event for one handler but not the others. You also need to add them for keyup (which can be combined as the code is the same):
$('#p_scents').on('keyup', '.quantity .cost', function() {
updateTotal();
});
IMPORTANT: Your code here is not matching a specific row. Also use #Barmar's fix like this to pass the current row:
$('#p_scents').on('keyup', '.quantity .cost', function() {
updateTotal($(this).closest('tr'));
});
Update: As Regent mentions below, you should not use document but use #p_scents for your delegated event handler:
$('#p_scents').on('click', '.remScnt', function()
A delegated event should be attached to the closest non-changing ancestor (if one is convenient/available). This will give a very small speed increase as it stops lower in the DOM.
I also cleaned up the event handler doing the calculations which now using temp vars, for elements relative to the row, and looks like:
// Update the row total of a specific row
var updateTotal = function ($row) {
// Get the specific inputs
var $quantity = $('.quantity', $row);
var $cost = $('.cost', $row);
var $total = $('.total', $row);
var input1 = parseFloat($quantity.val());
var input2 = parseFloat($cost.val());
if (isNaN(input1) || isNaN(input2)) {
if (!input2) {
$total.val($quantity.val());
}
if (!input1) {
$total.val($cost.val());
}
} else {
$total.val(input1 * input2);
}
var total = input1 * input2;
$total.val(total);
};
Note: Without the missing data, I cannot easily test the code, but you should get the idea.
Grand total
To update the grand total, you need to iterate all .total fields and add them to the shipping cost:
var updateGrandTotal = function()
{
// Now update the grand total
var grandTotal = 0;
$('.total').each(function () {
grandTotal += parseFloat($(this).val());
});
var shipping = parseFloat($('.shippingcost').val());
$('.grandtotal').val(grandTotal + shipping);
}
As you will want to update the grand total when the shipping changes, I refactored it out so it could also be called from a keyup on the shipping:
$('.shippingcost').keyup(function(){
updateGrandTotal();
});
The other issue is the autocomplete (which I could not test without a real data feed):
Basically get the select event to refer to the current field's row and find the appropriate fields to update:
JSFiddle: http://jsfiddle.net/TrueBlueAussie/vx15mr4n/23/
select: function (evt, ui) {
// when a product is selected, populate related fields in this form
var $tr = $(this).closest("tr");
$(".cost",$tr).val(ui.item.cost);
$(".product_id", $tr).val(ui.item.product_id);
$(".product_code", $tr).val(ui.item.product_code);
}
When updateTotal() uses $('.quantity').val() it gets the value of the first field with that class, not the one in the row that the user was typing in. You need to pass the row to the function. Also, since the elements are added dynamically, you need to use delegation for the event bindings.
$('#p_scents').on('keyup', '.quantity, .cost', function() {
updateTotal($(this).closest('tr'));
});
var updateTotal = function (row) {
var input1 = parseFloat($('.quantity', row).val());
var input2 = parseFloat($('.cost', row).val());
if (isNaN(input1) || isNaN(input2)) {
if(!input2){
$('.total', row).val(input1);
}
if(!input1){
$('.total', row).val($(input2);
}
} else {
$('.total', row).val(input1 * input2);
}
}
var output_total = $('.total', row);
var total = input1 + input2;
output_total.val(total);
};

Categories

Resources