jQuery set dynamically created input fields based on difference between 2 fields - javascript

Is there a way I can set input values of each dynamically created input fields based on a difference between 2 dynamically created fields. Below is my code and what am trying to achieve.
HTML
<table id="requested-wh-stock-table" class="table table-bordered table-hover dataTable" width="100%">
<thead>
<tr>
<th>Luminaire</th>
<th>Order Quantity</th>
<th>Delivered Qty</th>
<th>Back Order Qty</th>
</tr>
</thead>
<tbody>
#foreach ($salesorder as $request)
<tr>
<td><input type="text" class="form-control" name="luminaire" value="{{$request->luminaire}}" readonly></td>
<td><input type="number" class="form-control" name="order_quantity" id="order_quantity"
value="{{$request->quantity}}" readonly /></td>
<td><input type="number" class="form-control" name="delivered_quantity" id="delivered_quantity" value="" />
</td>
<td><input type="number" class="form-control" name="backorder_quantity" id="backorder_quantity" value=""
readonly /></td>
</tr>
#endforeach
</tbody>
</table>
jQuery
//Update Backorder qty based on Delivered Quantity amount
$(document).ready(function () {
$("#delivered_quantity").change(function () {
var backorder_quantity = $("#order_quantity").val() - $("#delivered_quantity").val();
$("#backorder_quantity").val(backorder_quantity);
});
});
Currently, it only updates the first field, it does not update other fields, is there a way I can loop through all fields and update Backorder field as I change the Delivered Quantity field?

If you are dynamically updated these fields within a loop, you will run into naming conflicts with the IDs. Instead, I would set the class name of each of the fields, and not the IDs:
<tr>
<td><input type="text" class="form-control" name="luminaire" value="10" readonly></td>
<td><input type="number" class="form-control order_quantity" name="order_quantity" id="order_quantity" value="20" readonly/></td>
<td><input type="number" class="form-control delivered_quantity" name="delivered_quantity" id="delivered_quantity" value=""/></td>
<td><input type="number" class="form-control backorder_quantity" name="backorder_quantity" id="backorder_quantity" value="" readonly/></td>
</tr>
Now you can attach an event listener in jQuery to every element with that class name, and you can reference it using the "this" keyword. Then sense they all have a parent that is a table row, we can use that to refer to the other input elements that are children of that parent element. Once we find the children in the row of the elements that you're targeting, we can update the values:
$(document).ready(function() {
$('.delivered_quantity').on('change', function() {
let parent = $(this).parents('tr');
let order_quantity = parent.find('.order_quantity');
let backQuant = parent.find('.backorder_quantity');
let backorder_quantity = order_quantity.val() - $(this).val();
backQuant.val(backorder_quantity);
});
});
We attach the change event to EACH of the delivered_quantity elements that you could potentially be targeting in your table. When any of them experience this event, the callback function above will occur. Next we get the parent element that is a table row. We then get the order_quantity and backorder_quantity elements that are children within the table row. We then calculate the backorder_quantity variable and then update the backorder_quantity element to match that value. Note that I had to put in some random values for your luminair and order_quantity sense we don't know what those values will be sense you're using them in a loop.

You should not use id on elements which are not unique. Since the inputs will be rendered multiple times (in rows), then I suggest to not use the id attribute. So let's try to use the name attribute instead for finding the DOM.
On the change event listener of delivered_quantity input, get the other fields in the same row. To do that, from this object inside the event handler, do seek the closest tr and then find the particular field from it's child.
$(document).ready(function() {
$("[name=delivered_quantity]").change(function() {
var order_quantity = $(this).closest('tr').find("[name=order_quantity]").val()
var delivered_quantity = $(this).closest('tr').find("[name=delivered_quantity]").val();
var backorder_quantity = order_quantity - delivered_quantity
$(this).closest('tr').find("[name=backorder_quantity]").val(backorder_quantity);
});
});

Related

Accessing an individual column in a row which is selected by default with a radio button on page load

With the code below, I am trying to access a particular column "quantity" from a row in a table. What is happening is one of the rows is selected by default when page loads while the rest of the rows can be selected when user chooses. I created a click event handler to handle manual selection.
When accessing the column with a class name, it returns nothing. I need to assign this value to an input box in the same form. I would attach the image of the row
Table Markup:
<tr valign="top" class="row6">
<td>
{if $tpl_order_details[lineitems].quantity > 1}
{if $radio_flag == "false"}
<input type="radio" name="line_item" class="radio_class" id="line_item" value="{$tpl_order_details[lineitems].mSku}" checked onclick="handleClick(this);"/>
{assign var=radio_flag value='true'}
{else}
<input type="radio" name="line_item" class="radio_class" id="line_item" value="{$tpl_order_details[lineitems].mSku}" onclick="handleClick(this);" />
{/if}
{/if}
</td>
<td>
{$tpl_order_details[lineitems].sku}
</td>
<td>
</td>
<td>{$tpl_order_details[lineitems].item_description}</td>
<td class="quantity_class" >{$tpl_order_details[lineitems].quantity}</td>
<td>{$tpl_order_details[lineitems].item_status}</td>
Markup with the Input field outside the loop:
<table>
<tr>
<td><label for="new_quantity">Enter New Quantity</label></td>
<td><input type="number" id="split_quantity" name="split_quantity"
min="1" max="6"></td>
<td><button type="submit" value="Save"
name="submit_action">Submit</button></td>
<td><button type="submit" value="Cancel"
name="submit_action">Cancel</button></td>
</tr>
</table>
JavaScript:
// This is to handle the radio button selected by default on page load.
$( document ).ready(function() {
var firstRadioValue = 0;
firstRadioValue = $("input[name='line_item']:checked").val();
$('input[name="split_quantity"]').attr('max', firstRadioValue);
var quantity = $(".radio_class").parent().find(".quantity_class").val();
alert(quantity);
});
// This is to handle the radio button that user actually chooses.
var currentRadioValue = 0;
function handleClick(line_item) {
alert('New value: ' + line_item.value);
currentRadioValue = line_item.value;
$('input[name="split_quantity"]').attr('max', currentRadioValue);
}
You're not going far enough up the tree to find the class. You have:
var quantity = $(".radio_class").parent().find(".quantity_class").val();
which gets you to the parent <td> The element you're looking for is a sibling of this:
<td class="quantity_class" >...
What you want to do is go one element higher (the table row), then find the class you're looking for from there, so use closest(). Note that .quantity_class doesn't have a value so you have to get the text in the table cell:
var quantity = $(".radio_class").closest('tr').find(".quantity_class").text();
In addition, I do not see any markup with the max attribute or any markup with the name of split_quantity.
EDIT - based on a conversation with the user it was found that there needed to be a number of changes. First, the table holding split_quantity needed to be identified so it could be targeted in the grander markup:
<table id="split_quantity_id">
<tr>
<td><label for="new_quantity">Enter New Quantity</label></td>
<td><input type="number" id="split_quantity" name="split_quantity" min="1" max="6"></td>
<td><button type="submit" value="Save" name="submit_action">Submit</button></td>
<td><button type="submit" value="Cancel" name="submit_action">Cancel</button></td>
</tr>
</table>
Then we got rid of the onclick="handleClick(this) inline JavaScript in favor of letting jQuery handle the click event. Finally we refactored the functions:
$(function() {
var firstRadioValue = 0;
firstRadioValue = $("input[name='line_item']:checked").closest('tr').find('.quantity_class').text();
$('input[name="split_quantity"]').attr('max', firstRadioValue);
var quantity = $(".radio_class").closest('tr').find(".quantity_class").text();
console.log(quantity);
$('table').delegate('.line_item', 'click', function(){
currentRadioValue = $(this).closest('tr').find('.quantity_class').text();
console.log(currentRadioValue);
$('#split_quantity_id').find('[name="split_quantity"]').attr('max', currentRadioValue);
});
});
NOTE: It was also discovered that the OP is using Smarty 2 which is an older version of Smarty using an older version of jQuery, so .delegate() is used instead of on().

JS Function only appends one row

I would like my js to add a row every time the user adds their initials. My code works the first time the user enters their initials, a new row is created under the first row, but then does not add anymore. I am not sure what i need to do.
My JS code:
(function(){
var counter = 1;
$("#preformedBy").change(function(){
$('#timeStamp').html(new Date().toLocaleString());
$('#harvestedCannabis > tbody:last-child').append('<tr><td><input type="number" id="toteNum" readonly></td><td><input type="number" step=".1">' +
'</td><td><input type="number" step=".1"></td><td><input type="number" step=".1"></td><td><input type="number" step=".1"></td><td>' +
'<input type="text"></td><td><input type="text" id="preformedBy"></td><td id="timeStamp"><input type="text" readonly></td></tr>');
counter = counter + 1;
$('#toteNum').html(counter)
})
});
My HTML:
<table id="harvestedCannabis">
<tr>
<th>Tote #</th>
<th>Flowers</th>
<th>Trim A</th>
<th>Trim B</th>
<th>Waste</th>
<th>Originating Line(A,B,C)</th>
<th>Preformed By</th>
<th>Time Stamp</th>
</tr>
<tr>
<td id="toteNum"><input type="number" value="1" readonly></td>
<td><input type="number" step=".1"></td>
<td><input type="number" step=".1"></td>
<td><input type="number" step=".1"></td>
<td><input type="number" step=".1"></td>
<td><input type="text"></td>
<td><input type="text" id="preformedBy"></td>
<td id="timeStamp"><input type="text" readonly></td>
</tr>
</table>
I would like the table to keep appending new row as many times as the user requires, automatically after they insert their initials
You have two main issues with your code. I'll explain them, but first take a look at this fiddle I made with your code, this version actually works:
https://jsfiddle.net/49Ln0qcf/#&togetherjs=2hdIlfBaC0
So now lets explore where you went wrong:
1.
You're listening to an ID attribute for your onChange event. It works the first time around because at that point in time you only have one element with id="preformedBy", but after you add your second row you then have TWO elements with the same ID. jQuery is listening to the first instance of the ID in the dom, thus your additional input fields are not being listened to. So, replace your id attribute with a class, then your .preformedBy selector will work past your second iteration.
2.
Taking the step above alone will not fix your code. To get more than the first iteration to work, you'll need to listen to the parent element of your .preformedBy class. In your code, you're listening to preformedBy directly like so:
$("#preformedBy").change(function(){
The problem here is that on page load, jquery is only aware of the dom elements that exist on page load, thus the first and only instance of preformedBy. So jQuery will continue to listen to that element and ONLY that element because it knows nothing of the elements you've added to the dom AFTER page load. In order to get jQuery to listen to ALL instances of preformedBy, you need to listen to a parent selector. Notice in my code, I'm listening to preformedBy like so:
$("#harvestedCannabis").on('change', '.preformedBy', function(){
The key difference is that my code listens to change events on the parent element, but specifically listens to any and all occurrences of '.preformedBy' within that parent element. As where your code is listening to a unique element with the preformedBy selector.
I hope this helps.
Finalized code that works:
html:
<table id="harvestedCannabis">
<tr>
<th>Tote #</th>
<th>Flowers</th>
<th>Trim A</th>
<th>Trim B</th>
<th>Waste</th>
<th>Originating Line(A,B,C)</th>
<th>Preformed By</th>
<th>Time Stamp</th>
</tr>
<tr>
<td id="toteNum1"><input type="number" value="1" readonly></td>
<td><input type="number" step=".1"></td>
<td><input type="number" step=".1"></td>
<td><input type="number" step=".1"></td>
<td><input type="number" step=".1"></td>
<td><input type="text"></td>
<td><input type="text" class="preformedBy"></td>
<td id="timeStamp1"><input type="text" readonly></td>
</tr>
</table>
jQuery:
var counter = 1;
$("#harvestedCannabis").on('change', '.preformedBy', function(){
$('#timeStamp'+counter).html(new Date().toLocaleString());
$('#harvestedCannabis > tbody:last-child').append('<tr><td><input type="number" id="toteNum'+(counter + 1)+'" readonly></td><td><input type="number" step=".1">' +
'</td><td><input type="number" step=".1"></td><td><input type="number" step=".1"></td><td><input type="number" step=".1"></td><td>' +
'<input type="text"></td><td><input type="text" class="preformedBy"></td><td id="timeStamp'+(counter + 1)+'"><input type="text" readonly></td></tr>');
$('#toteNum'+(counter + 1)).val(counter + 1);
counter = counter + 1;
});
Your are changing all this element #toteNum with counter value
<td id="toteNum"><input type="number" value="1" readonly></td>
When you create a new element you need to rebind the listeners.
When your code works, your HTML will have 2 #preformedBy elements, you may have unique ids on the same page.
Try the insertRow() and insertCell() methods.
According to W3Schools example:
https://www.w3schools.com/jsref/met_table_insertrow.asp
Remove the id from your html and js code and use a class selector to trigger the change function, then it should work.

How to clone form elements with auto increamented id to all elements

I have a form under a . I want to clone this and append dynamically in another and so on dynamically. Also I need to assign auto incremented id to all form elements too. Apart from pure javascript I can not use any jQuery or any other library.
Here is my HTML
<tr id="repeat">
<td><input type="text" id="fieldName" /></td>
<td>
<select name="fieldType" id="fieldType">
<option value="string">String</option>
</select>
</td>
<td><input type="radio" id="mandatory" name="mandatory" value="true" /><input type="radio" id="mandatory" name="mandatory" value="false" /></td>
<td>Delete Button</td>
</tr>
Here is my JavaScript
var i = 0;
this.view.findById("start").addEventHandler("click", function () {
var original = document.getElementById('repeat');
var clone = original.cloneNode(true);
original.parentNode.appendChild(clone);
})
Presently I can cloned the form elements in <tr id="repeated1"> dynamically and so on, but unable to assign auto incremented id to input box and select box . Also unable to assign auto incremented name to the radio buttons dynamically
You can change Id or another attribute as you want.
but for your code my solution is using querySelectorAll to get element and change it's Id, something like below code, it is tested and works nice:
Based on this HTML design code and JS function:
function MakeElementsWithDifferentId() {
for (var i = 1; i < 10; i++) {
var original = document.getElementById('repeat');
var clone = original.cloneNode(true);
clone.id="repeat"+i;
clone.querySelectorAll('[id="fieldName"]')[0].id ="fieldName"+i;
clone.querySelectorAll('[id="fieldType"]')[0].id ="fieldType"+i;
clone.querySelectorAll('[id="mandatory"]')[0].id ="mandatory"+i;
clone.children[2].children[0].name="mandatoryName"+i; //To change the radio name also
original.parentNode.appendChild(clone);
}
}
MakeElementsWithDifferentId();
<table>
<tr id="repeat">
<td><input type="text" id="fieldName" /></td>
<td>
<select name="fieldType" id="fieldType">
<option value="string">String</option>
</select>
</td>
<td><input type="radio" id="mandatory" name="mandatory" value="true" /> </td>
<td>Delete Button</td>
</tr>
</table>
the MakeElementsWithDifferentId() function make 10 batch elements with different Ids.
the JSFiddle Test
after run you can right click on element that you want and see the Id by inspect element.
Note:
Instead of clone.querySelectorAll('[id="fieldName"]')[0] it's better to get element by querySelector like clone.querySelector('[id="fieldName"]')
Hope will help you.

How to add row in html table on top of specific row?

I have a table, and each row has a button to add a new row on top of it. Each row has new inputs.
I know how to add a row on top of the table, but not on top of each row that I'm clicking on the button. Would anyone have a tip on how to solve it? I might be able to do it, but the solution I see is very complicated, and I'm sure there must be a smarter solution.
Oh, also I don't know how to update the parameter sent in the insertNewRow(id) function.
So far this is what I have:
<script type="text/javascript">
function insertNewRow(id){
var row = document.getElementById("bottomRow");
var newrow = row.cloneNode(true);
console.log(newrow);
var newInputs = newrow.getElementsByTagName('input');
var allRows = row.parentNode.getElementsByTagName('tr');
row.parentNode.insertBefore(newrow, row);
var i=row.rowIndex;
console.log(i);
}
</script>
<table id="myTable">
<tr>
<td>Title1:</td>
<td></td>
<td>Title2:</td>
<td></td>
<td>Title3:</td>
<td></td>
<td></td>
</tr>
<tr>
<td><input class="c1" readonly maxlength="9" size="7" id="gTop" type="text" value ="11"></td>
<td> <-></td>
<td id="l1"><input class="c2" style="width:35px;" maxlength="9" size="7" type="text" id="lTop" value="33"></td>
<td>=</td>
<td id="rv1"><input id="rvTop" input class="c2" style="width:105px;" maxlength="100" size="37" type="text" value="blahblahblah"></td>
<td></td>
<td>x</td>
</tr>
<tr id="bottomRow">
<td><input class="c1" readonly maxlength="9" size="7" id="gBottom" type="text" value =""></td>
<td> </td>
<td id="l1"><input class="c2" style="width:35px;" maxlength="9" size="7" type="text" id="lBottom" value="11"></td>
<td>=</td>
<td id="rv1"><input id="rvBottom" input class="c2" style="width:105px;" maxlength="100" size="37" type="text" value="blahblahblah"></td>
<td><button type="button" onclick="insertNewRow(1)">+</button></td>
<td>x</td>
</tr>
</table>
In the onclick attribute, instead of just calling insertNewRow(), do something like
insertNewRow.apply(this);
The this keyword inside the onclick attribute is a reference of the clicked element. With insertNewRow.apply(this), we'll be calling insertNewRow() and at the same time, assign the this keyword inside that function call to the clicked element or in this case, the button (if we don't do that, this inside insertNewRow() will be a reference to the Window object instead). Then in, your insertNewRow() function, check if the current element being clicked on is a tr element. If not, go up by one level and see if that element is a tr element. Keep doing that until you get to the first tr element. So, basically you'll be searching for the closest tr element.
<button type="button" onclick="insertNewRow.apply(this);">+</button>
function insertNewRow(){
var row = null,
el = this;
// Get the closest tr element
while (row === null)
{
if (el.tagName.toLowerCase() === 'tr')
{
row = el; // row is now the closest tr element
break;
}
el = el.parentNode;
}
// Rest of the code here
}​
JsFiddle
If you're still not sure what Function.apply() is, take a look at the documentation here.

JavaScript: how to access the textbox in the second row of the table

I have an html code like this -
<table border="0" cellspacing="2" cellpadding="2" width="99%" id="subAccTable">
<tr>
<h2>Sub Accounts</h2>
</tr>
<tr>
<th>action </th>
<th>account</th>
<th>homeDir</th>
<th>primaryGroup</th>
</tr>
<tr>
<td><input type="hidden" name="vtierId" value="" /></td>
<td><input type="text" name="subAcc"
value=""/></td>
<td><input type="text" name="subHomeDir"
value=""/></td>
<td><input type="text" name="subPriGroup"
value=""/></td>
</tr>
</table>
Now i want to fill the values of textboxes named subAcc, subHomeDir, subPriGroup using javascript. How can i do it ?
There are multiple ways to get the proper DOMElement; including:
Giving each element an id and getting it using document.getElementById
Using document.getElementsByName. This is not preferred since there can be multiple elements with the same name, however there can be only one with the same id.
Using the form directly. For example if your form's name is form1: form1.subAcc
Using document.getElementsByTagName('input') and then getting the proper index.
I'd recommend using the id to retrieve the proper element.
The easiest way would be to give these textboxes a unique id, then reference them like this:
<input type="text" id="subHomeDir" name="subHomeDir" value=""/>
var tb = document.getElementById("subHomeDir");
tb.value = "foo";
If you're stuck with the names only, then you can use document.getElementsByName, just remember, this will return a collection of elements (since names are not necessarily unique), which you'll have to index:
var tb = document.getElementsByName("subHomeDir")[0];
tb.value = "foo";

Categories