jQuery Clone Table Row BUT with Multiple Tables on Page - javascript

I have a page containing:
<div class="my_div">
<table>
<tr>
<th>Title 1</th><th>Title 2</th><th>Title 3</th>
</tr>
<tr>
<td><input type="input" name="set[1][arg1]" value="X"></td>
<td><input type="input" name="set[1][arg2]" value="Y"></td>
<td><input type="input" name="set[1][arg3]" value="Z"></td>
</tr>
<tr>
<td><input type="input" name="set[2][arg1]" value="X"></td>
<td><input type="input" name="set[2][arg2]" value="Y"></td>
<td><input type="input" name="set[2][arg3]" value="Z"></td>
</tr>
<tr>
<td><input type="input" name="set[3][arg1]" value="X"></td>
<td><input type="input" name="set[3][arg2]" value="Y"></td>
<td><input type="input" name="set[3][arg3]" value="Z"></td>
</tr>
</table>
Add another Set
</div>
<div class="my_div">
<table>
<tr>
<th>Title 1</th><th>Title 2</th><th>Title 3</th>
</tr>
<tr>
<td><input type="input" name="set[4][arg1]" value="X"></td>
<td><input type="input" name="set[4][arg2]" value="Y"></td>
<td><input type="input" name="set[4][arg3]" value="Z"></td>
</tr>
<tr>
<td><input type="input" name="set[5][arg1]" value="X"></td>
<td><input type="input" name="set[5][arg2]" value="Y"></td>
<td><input type="input" name="set[5][arg3]" value="Z"></td>
</tr>
<tr>
<td><input type="input" name="set[6][arg1]" value="X"></td>
<td><input type="input" name="set[6][arg2]" value="Y"></td>
<td><input type="input" name="set[6][arg3]" value="Z"></td>
</tr>
</table>
Add another Set
</div>
Two (or more) divs, containing a table each, plus n rows, each containing inputs. The inputs you already see are dynamically created from data in the db.
I would like to be able to just add a new <tr> when the link below any table is clicked. The catch being that the table which will recieve the new row is the one immediately above the link clicked.
I did think about giving each table a unique id which matches the id of the link but am unsure how in the jQuery to then recognise that a link with a random id has been clicked.
Then i thought maybe I could use the closest functionality and traverse backwards from the link to the table above it but I don't think that works. (maybe it does?)
Also, when I add the new row, it needs to be blank, which I think I could figure out, once I manage to clone the last (or any for that matter) row and append it to the end of the relevant table. E.g. new row:
<tr>
<td><input type="input" name="newSet[][arg1]" value=""></td>
<td><input type="input" name="newSet[][arg2]" value=""></td>
<td><input type="input" name="newSet[][arg3]" value=""></td>
</tr>
Hope it makes sense what I am asking.
Thanks in advance.
Jon

First, add a class addSet to your links and remove the id or make it unique. Repeated ids is not a valid markup. After doing this, I'd say this should work
$('.addSet').click(function(e) {
e.preventDefault();
var $table = $(this).prev();
var $row = $table.find('tr:last');
var $clonedRow = $row.clone();
$clonedRow.find('input').each(function(index) {
var $this = $(this);
$this.val('');
$this.prop('name','set[][arg' + (index + 1) + ']' );
})
$table.append($clonedRow);
});
DEMO

DEMO
As pointed out in the comments, please change id="addSet" to class="addSet" to get rid of duplicate ID's. Make a clone of the last row .... there should be at least one row in the table, otherwise this part will fail. Then fix the name and value of each input element in the clone. You can either change the current value with .val() or the default/initial value with .attr() or removeAttr('value').
Here is the code you need:
$(function() {
$(document).on('click', 'a.addSet', function(e) {
e.preventDefault();
var tr = $(this).closest('div.my_div').find('tr').last().clone();
tr.find('input').attr('name', function() {
return $(this).attr('name').replace(/set\[\d{1,}\]/g,'newSet[]');
})
.each(function() {
$(this).val('');
});
$(this).closest('div.my_div').find('table tbody').append( tr );
});
});

you can do it by adding a class to the link as id must be unique:
HTML:
<div class="my_div">
<table>
<tr>
<th>Title 1</th>
<th>Title 2</th>
<th>Title 3</th>
</tr>
<tr>
<td>
<input type="input" name="set[1][arg1]" value="X" />
</td>
<td>
<input type="input" name="set[1][arg2]" value="Y" />
</td>
<td>
<input type="input" name="set[1][arg3]" value="Z" />
</td>
</tr>
<tr>
<td>
<input type="input" name="set[2][arg1]" value="X" />
</td>
<td>
<input type="input" name="set[2][arg2]" value="Y" />
</td>
<td>
<input type="input" name="set[2][arg3]" value="Z" />
</td>
</tr>
<tr>
<td>
<input type="input" name="set[3][arg1]" value="X" />
</td>
<td>
<input type="input" name="set[3][arg2]" value="Y" />
</td>
<td>
<input type="input" name="set[3][arg3]" value="Z" />
</td>
</tr>
</table> Add another Set
</div>
<div class="my_div">
<table>
<tr>
<th>Title 1</th>
<th>Title 2</th>
<th>Title 3</th>
</tr>
<tr>
<td>
<input type="input" name="set[4][arg1]" value="X" />
</td>
<td>
<input type="input" name="set[4][arg2]" value="Y" />
</td>
<td>
<input type="input" name="set[4][arg3]" value="Z" />
</td>
</tr>
<tr>
<td>
<input type="input" name="set[5][arg1]" value="X" />
</td>
<td>
<input type="input" name="set[5][arg2]" value="Y" />
</td>
<td>
<input type="input" name="set[5][arg3]" value="Z" />
</td>
</tr>
<tr>
<td>
<input type="input" name="set[6][arg1]" value="X" />
</td>
<td>
<input type="input" name="set[6][arg2]" value="Y" />
</td>
<td>
<input type="input" name="set[6][arg3]" value="Z" />
</td>
</tr>
</table> Add another Set
</div>
JQUERY:
$(".addSet").click(function () {
$(this).prev("table").append('<tr><td><input type="input" name="newSet[][arg1]" value=""></td><td><input type="input" name="newSet[][arg2]" value=""></td><td><input type="input" name="newSet[][arg3]" value=""></td></tr>');
})
FIDDLE:
http://jsfiddle.net/kbxekrjc/

I am answering my own question because I used a combination of two of the other provided answers (#ClaudioRedi & #user3558931)
$('.addSet').click(function(e) {
e.preventDefault();
var $table = $(this).prev();
var $row = $table.find('tr:last');
var $clonedRow = $row.clone();
$clonedRow.find('input').attr('name', function() {
return $(this).attr('name').replace(/set\[\d{1,}\]/g,'newSet[]');
})
.each(function() {
$(this).val('');
});
$clonedRow.hide();
$table.append($clonedRow);
$clonedRow.show('slow');
});

Related

javascript equivalent to jquery closest().find()

<tr>
<td><input type="text" class="rate" oninput="priceChanged(this)"> </td>
<td><input type="text" class="quantity"></td>
<td><input type="text" class="total"> </td>
</tr>
I can find the quantity textbox with jquery-
var quantityTextbox = $('.rate').closest('tr').find('.quantity');
I would like to do it now with pure javascript.
I am newcomer in the pure javascript world.
Any idea?
You can use querySelector & .closest() for this like:
var quantityTextbox = document.querySelector('.rate').closest('tr').querySelector('.quantity')
console.log(quantityTextbox.value)
<table>
<tr>
<td><input type="text" class="rate" oninput="priceChanged(this)"> </td>
<td><input type="text" class="quantity" value="10"></td>
<td><input type="text" class="total"> </td>
</tr>
</table>
If you are calling this inside priceChanged() function, then you can use:
function priceChanged(rate){
var quantityTextbox = rate.closest('tr').querySelector('.quantity')
}
as you are already passing this inside priceChanged() function.
function priceChanged(rate) {
var quantityTextbox = rate.closest('tr').querySelector('.quantity')
console.log(quantityTextbox.value)
}
<table>
<tr>
<td><input type="text" class="rate" oninput="priceChanged(this)"> </td>
<td><input type="text" class="quantity" value="10"></td>
<td><input type="text" class="total"> </td>
</tr>
</table>

How to access element attribute whose display is none?

I am trying to access the attribute/value of 'schoolidx' that is not hidden, when add button is clicked; however I am having hard time accessing it.
Can someone guide me please? I am trying to get only "1", or "2", or "3" depending on which one is not hidden ("display: none;"). In this case, "1".
Tried different methods:
let schoolIndex = $('#schoolTableBody > tr:not([style*="display: none"])').attr("schoolidx"),
schoolIndex2 = $('tr').filter(function(){ return $(this).css("display") != "none";}).attr("schoolidx"),
schoolIndex3 = $('tr').filter(function(){ return $(this).css("display") != "none";}).attr("schoolidx"),
schoolIndex4 = $("#schoolTableBody > tr:visible")
<table class="table table-striped table-hover table-condensed" id="schoolTable">
<thead>
<tr>
<th> </th>
<th>School Name</th>
<th>Country</th>
</tr>
</thead>
<tbody id="schoolTableBody">
<tr class="school-row" style="">
<td><button id="addSchoolBtn" title="Add" style="width:50px"/></td>
<td><input type="text" name="sName" id="sName"></td>
<td><input type="text" name="Country" id="Country"></td>
</tr>
<tr schoolidx="1" style="">
<td> </td>
<td><input type="hidden" name="sName" value="SK">SK</td>
<td><input type="hidden" name="Country" value="US">US</td>
</tr>
<tr schoolidx="1" style="">
<td> </td>
<td><input type="hidden" name="sName" value="JS">JS</td>
<td><input type="hidden" name="Country" value="US">US</td>
</tr>
<tr schoolidx="2" style="display: none;">
<td> </td>
<td><input type="hidden" name="sName" value="CAS">CAS</td>
<td><input type="hidden" name="Country" value="CA">CA</td>
</tr>
<tr schoolidx="2" style="display: none;">
<td> </td>
<td><input type="hidden" name="sName" value="AM">AM</td>
<td><input type="hidden" name="Country" value="CA">CA</td>
</tr>
<tr schoolidx="3" style="display: none;">
<td> </td>
<td><input type="hidden" name="sName" value="BAS">BAS</td>
<td><input type="hidden" name="Country" value="BR">BR</td>
</tr>
</tbody>
</table>
Instead of attempting to search by styling, perhaps you could add an 'active' class when you unhide a given row, and remove it when you hide it again.
You can then search using jQuery. var schoolid = $("tr.active").prop("schoolidx");
Have a look at addClass and removeClass. I assume you already have the ability to hide each row. Just add those two functions to that bit of code.
Note that I have changed your 'attribute' to a valid data attribute
For the JS, we have to make sure we're only selecting the tr's within the tbody but not the first tr as thats where the add button is.
Then do an if() within an onclick to check to see if the display is set to none
<button> aren't self closing, they require a </button>
document.getElementById('addSchoolBtn').addEventListener('click', () => {
document.querySelectorAll('#schoolTableBody tr:not(.school-row)').forEach(tr => {
if (tr.style.display !== "none") alert(tr.dataset.schoolidx)
})
})
<table class="table table-striped table-hover table-condensed" id="schoolTable">
<thead>
<tr>
<th> </th>
<th>School Name</th>
<th>Country</th>
</tr>
</thead>
<tbody id="schoolTableBody">
<tr class="school-row" style="">
<td><button id="addSchoolBtn" title="Add" style="width:50px">Add</button></td>
<td><input type="text" name="sName" id="sName"></td>
<td><input type="text" name="Country" id="Country"></td>
</tr>
<tr data-schoolidx="1" style="">
<td> </td>
<td><input type="hidden" name="sName" value="SK">SK</td>
<td><input type="hidden" name="Country" value="US">US</td>
</tr>
<tr data-schoolidx="1" style="">
<td> </td>
<td><input type="hidden" name="sName" value="JS">JS</td>
<td><input type="hidden" name="Country" value="US">US</td>
</tr>
<tr data-schoolidx="2" style="display: none;">
<td> </td>
<td><input type="hidden" name="sName" value="CAS">CAS</td>
<td><input type="hidden" name="Country" value="CA">CA</td>
</tr>
<tr data-schoolidx="2" style="display: none;">
<td> </td>
<td><input type="hidden" name="sName" value="AM">AM</td>
<td><input type="hidden" name="Country" value="CA">CA</td>
</tr>
<tr data-schoolidx="3" style="display: none;">
<td> </td>
<td><input type="hidden" name="sName" value="BAS">BAS</td>
<td><input type="hidden" name="Country" value="BR">BR</td>
</tr>
</tbody>

How to customize jAutoCalc plugin

I have a simple question regarding jAutoCalc, my question can be answered in two ways:
1> How to customize the jAutoCalc plugin so that we can make it able to be used for input array names instead of just names.
my code is here:
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="http://rawgit.com/c17r/jAutoCalc/master/jAutoCalc.js"></script>
<script type="text/javascript">
<!--
$(document).ready(function() {
function autoCalcSetup() {
$('form[name=cart]').jAutoCalc('destroy');
$('form[name=cart] tr[name=line_items]').jAutoCalc({
keyEventsFire: true,
decimalPlaces: 2,
emptyAsZero: true
});
$('form[name=cart]').jAutoCalc({
decimalPlaces: 2
});
}
autoCalcSetup();
$('button[name=remove]').click(function(e) {
e.preventDefault();
var form = $(this).parents('form')
$(this).parents('tr').remove();
autoCalcSetup();
});
$('button[name=add]').click(function(e) {
e.preventDefault();
var $table = $(this).parents('table');
var $top = $table.find('tr[name=line_items]').first();
var $new = $top.clone(true);
$new.jAutoCalc('destroy');
$new.insertBefore($top);
$new.find('input[type=text]').val('');
autoCalcSetup();
});
});
</script>
</head>
<body>
<form name="cart">
<table name="cart">
<tr>
<th></th>
<th>Item</th>
<th>Qty</th>
<th>Price</th>
<th> </th>
<th>Item Total</th>
</tr>
<tr name="line_items">
<td><button name="remove">Remove</button></td>
<td>Stuff</td>
<td><input type="text" name="qty" value="1"></td>
<td><input type="text" name="price" value="9.99"></td>
<td> </td>
<td><input type="text" name="item_total" value="" jAutoCalc="{qty} * {price}"></td>
</tr>
<tr name="line_items">
<td><button name="remove">Remove</button></td>
<td>More Stuff</td>
<td><input type="text" name="qty" value="2"></td>
<td><input type="text" name="price" value="12.50"></td>
<td> </td>
<td><input type="text" name="item_total" value="" jAutoCalc="{qty} * {price}"></td>
</tr>
<tr name="line_items">
<td><button name="remove">Remove</button></td>
<td>And More Stuff</td>
<td><input type="text" name="qty" value="3"></td>
<td><input type="text" name="price" value="99.99"></td>
<td> </td>
<td><input type="text" name="item_total" value="" jAutoCalc="{qty} * {price}"></td>
</tr>
<tr>
<td colspan="3"> </td>
<td>Subtotal</td>
<td> </td>
<td><input type="text" name="sub_total" value="" jAutoCalc="SUM({item_total})"></td>
</tr>
<tr>
<td colspan="3"> </td>
<td>
Tax:
<select name="tax">
<option value=".06">CT Tax</option>
<option selected value=".00">Tax Free</option>
</select>
</td>
<td> </td>
<td><input type="text" name="tax_total" value="" jAutoCalc="{sub_total} * {tax}"></td>
</tr>
<tr>
<td colspan="3"> </td>
<td>Total</td>
<td> </td>
<td><input type="text" name="grand_total" value="" jAutoCalc="{sub_total} + {tax_total}"></td>
</tr>
<tr>
<td colspan="99"><button name="add">Add Row</button></td>
</tr>
</table>
</form>
</body>
</html>
since the names are same for dynamically generated input's i want use input array. The problem is that if i do so then I'm unable to use the plugin features!
2> The question can be answered in second way by providing methods to use plugin while using input arrays
I know its an old post but maybe others may have same issue.
Try to open jautocalc.js find this function "getFieldSelector(field)" and edit this code.
return ':input[name="' + field + '"]';
to
return ':input[name="' + field + '[]"]';
I think the whole problem is with javascript
the javascript should be like
$(document).ready(function(){
$('.item_total').keyup(function(){
$('your result input name here).text($('.item_total').val() * 1.5);
});
});
this link will help you:
http://jsfiddle.net/7BDwP/
You will get idea from the above link what i am trying to say

Trying to find previous DOM elements and get input value jquery

I am trying to create a table that when a user click update, it will get the first and second input value. I am trying to use prev to find the first two DOM element and get the value, but fail, what should I do? Any help is appreciated.
$('.update_button').on("click",function(){
var update_val_1 = $(this).prev().find('input:first').val();
var update_val_2 = $(this).prev().find('input:nth-child(2)').val();
alert(update_val_1);
alert(update_val_2);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<tr class="gridtable">
<td><input type="text" value="apple" /></td>
<td><input type="text" value="one" /></td>
<td><button type="button" class="update_button">UPDATE</button></td>
</tr>
<tr class="gridtable">
<td><input type="text" value="banana" /></td>
<td><input type="text" value="three" /></td>
<td><button type="button" class="update_button">UPDATE</button></td>
</tr>
<tr class="gridtable">
<td><input type="text" value="berry" /></td>
<td><input type="text" value="ten" /></td>
<td><button type="button" class="update_button">UPDATE</button></td>
</tr>
The problem is that prev looks for sibling nodes. Your input elements are in different td's so they aren't siblings. Instead, you need to go to the parent row then grab the inputs from there.
Explicit example:
$('.update_button').on("click", function() {
var $parentRow = $(this).closest('.gridtable');
var $firstCell = $parentRow.find('td:first-child');
var $secondCell = $parentRow.find('td:nth-child(2)');
var $firstInput = $firstCell.find('input');
var $secondInput = $secondCell.find('input');
var update_val_1 = $firstInput.val();
var update_val_2 = $secondInput.val();
console.log(update_val_1);
console.log(update_val_2);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr class="gridtable">
<td>
<input type="text" value="apple" />
</td>
<td>
<input type="text" value="one" />
</td>
<td>
<button type="button" class="update_button">UPDATE</button>
</td>
</tr>
<tr class="gridtable">
<td>
<input type="text" value="banana" />
</td>
<td>
<input type="text" value="three" />
</td>
<td>
<button type="button" class="update_button">UPDATE</button>
</td>
</tr>
<tr class="gridtable">
<td>
<input type="text" value="berry" />
</td>
<td>
<input type="text" value="ten" />
</td>
<td>
<button type="button" class="update_button">UPDATE</button>
</td>
</tr>
</table>
Simplified example:
$('.update_button').on("click", function() {
var $parentRow = $(this).closest('.gridtable');
var update_val_1 = $parentRow.find('td:first-child input').val();
var update_val_2 = $parentRow.find('td:nth-child(2) input').val();
console.log(update_val_1);
console.log(update_val_2);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr class="gridtable">
<td>
<input type="text" value="apple" />
</td>
<td>
<input type="text" value="one" />
</td>
<td>
<button type="button" class="update_button">UPDATE</button>
</td>
</tr>
<tr class="gridtable">
<td>
<input type="text" value="banana" />
</td>
<td>
<input type="text" value="three" />
</td>
<td>
<button type="button" class="update_button">UPDATE</button>
</td>
</tr>
<tr class="gridtable">
<td>
<input type="text" value="berry" />
</td>
<td>
<input type="text" value="ten" />
</td>
<td>
<button type="button" class="update_button">UPDATE</button>
</td>
</tr>
</table>
I'm a big fan of the .closest(selector) and .find('selector') methods.
The first one goes up the dom until it finds the first match of the given selector.
The second one goes down the dom and finds all matches.
.eq(index) is like array[index] for jQuery. It takes a collection of jQuery elements and returns the one at the given index.
$('.update_button').on("click",function(){
var inputs = $(this).closest('.gridtable').find('input');
var value1 = inputs.eq(0).val();
var value2 = inputs.eq(1).val();
});

Disabling certain inputs in table on button press

I currently have a table that contains a few values, 2 input fields and a button for each row in that table. What I want to happen is that when I press the button in the third row, the input fields in the third row become disabled. The other rows should remain unaffected. Unfortunately, due to the nature of the program, adding ID's to the inputs and buttons is not possible.
Does anyone know of a good way to go about this?
<tr>
<td>Text A</td>
<td>Text B</td>
<td><input class="editable"></td>
<td>Text C</td>
<td><input class="editable></td>
<td>Text D</td>
<td><button class="disableInput">OK</button></td>
<tr>
I have ~40 rows like this
Also, due to the table constantly autosaving to a database (for the input) the table gets refreshed every ~0.5 seconds
$(tableId).on("click", "button", function(){
$(this).closest("tr").find("input").attr("disabled", true);
})
Since you are using jQuery, you can do something like this:
$(document).ready(function() {
$("table td .btn").click(function() {
if ($(this).closest("tr").find("input").attr("disabled") === "disabled"){
$(this).closest("tr").find("input").removeAttr("disabled", "disabled");
$(this).closest("tr").find("button").text("Disbale");
}
else{
$(this).closest("tr").find("input").attr("disabled", "disabled");
$(this).closest("tr").find("button").text("Enable");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td>
<input type="text" />
</td>
<td>
<input type="text" />
</td>
<td>
<button class="btn" type="button" />Disable</button>
</td>
</tr>
<tr>
<td>
<input type="text" />
</td>
<td>
<input type="text" />
</td>
<td>
<button class="btn" type="button" />Disable</button>
</td>
</tr>
<tr>
<td>
<input type="text" />
</td>
<td>
<input type="text" />
</td>
<td>
<button class="btn" type="button" />Disable</button>
</td>
</tr>
</tbody>
</table>
You can do this via traversing the DOM.
$('.disableInput').on('click',function(){
var input = $(this).closest('tr').find('input');
var currstatus = input.prop('disabled');
input.prop('disabled',!currstatus);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table>
<tr>
<td><input type="text" name="somthing[]"></td>
<td><input type="text" name="something[]"></td>
<td><button class="disableInput">Toggle Input</button></td>
</tr>
<tr>
<td><input type="text" name="somthing[]"></td>
<td><input type="text" name="something[]"></td>
<td><button class="disableInput">Toggle Input</button></td>
</tr>
<tr>
<td><input type="text" name="somthing[]"></td>
<td><input type="text" name="something[]"></td>
<td><button class="disableInput">Toggle Input</button></td>
</tr>
</table>

Categories