Duplicating Div always duplicates - javascript

TO BETTER UNDERSTAND MY QUESTION AND SEE CODE VISIT THE FIDDLE: http://jsfiddle.net/dnyXC/
I have a script (below) that allows you to click a icon and it duplicates the table allowing for more inputs on the included form. This issue is, once you click the icon once to duplicate it, anywhere you click on the table regardless of position duplicates the table again.
document.getElementById('line-duplicate').onclick = duplicate;
var i = 0;
function duplicate() {
var original = document.getElementById('item-table' + i);
var clone = original.cloneNode(true); // "deep" clone
clone.id = "item-table" + ++i; // there can only be one element with an ID
clone.onclick = duplicate; // event handlers are not cloned
original.parentNode.appendChild(clone);
}
Here is the html for the table:
<table class="table" id="item-table0">
<tr>
<td>Item Name</td>
<td>Qty/Hrs</td>
<td>Rate</td>
<td>Tax Rate</td>
<td>Type</td>
<td>Cost</td>
<td>Actions</td>
</tr>
<tr>
<td>
<input class="input-medium" type="text" name="" />
</td>
<td>
<input class="input-mini" type="text" name="" placeholder="1" />
</td>
<td>
<input class="input-mini" type="text" name="" placeholder="0.00" />
</td>
<td></td>
<td>
<select class="input-small" name="">
<option>Standard</option>
<option>Expense</option>
</select>
</td>
<td>$0.00</td>
<td><i class="icon-plus" style="cursor:pointer;" id="line-duplicate"></i> <i class="icon-trash pull-right"></i>
</a>
</td>
</tr>
endless duplication is fine, the issue is when you go to type another item into the form, you duplicate the table. I need it so that the only way to duplicate the table is by clicking the plus icon.
TO BETTER UNDERSTAND MY QUESTION AND SEE CODE VISIT THE FIDDLE: http://jsfiddle.net/dnyXC/

The issue is that you are binding the onclick for the entire duplicated row to the duplicate() function.
You should make line-duplicate a class (having multiple elements with the same ID is a bad thing), and use document.getElementsByClassName('line-duplicate') both inside and outside the function to bind the duplicate function to every single element with that class name, like so:
document.getElementsByClassName('line-duplicate')[0].onclick = duplicate;
var i = 0;
function duplicate() {
var original = document.getElementById('item-table' + i);
var clone = original.cloneNode(true); // "deep" clone
clone.id = "item-table" + ++i; // there can only be one element with an ID
original.parentNode.appendChild(clone);
var listOfLineDuplicateItems = document.getElementsByClassName('line-duplicate'); // this must be after the table has been appended to the DOM
for (var j = 0; j < listOfLineDuplicateItems.length; ++j) {
listOfLineDuplicateItems[i].onclick = duplicate;
}
}
Here's a JSFiddle.

Related

for statement keeps put first empty value

I'm trying to get only checked checkbox values
so I used for statement.
It goes well if I check from the first
but if I check from second It put empty value in array.
even I set this contidion, it still put empty value.
if (document.getElementsByName("check")[i].checked == true)
what is problem?
js
var arr_downloadName = new Array();
var chekced_download = 0;
$(".compress").click(function () {
var size = document.getElementsByName("check").length;
for (var i = 0; i < size; i++) {
if (document.getElementsByName("check")[i].checked == true) {
arr_downloadName[i] = document.getElementsByName("check")[i].value;
chekced_download++
}
}
});
html
<tr>
<td id="10Mb.dat"><input type="checkbox" name='check' value='10Mb.dat'
data-url="https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73751/world.topo.bathy.200407.3x21600x10800.jpg"/>File10MB
</td>
</tr>
<tr>
<td id="100mb.bin"><input type="checkbox" name='check' value='100mb.bin'
data-url="http://speedtest-ny.turnkeyinternet.net/100mb.bin"/>File100MB
</td>
</tr>
<tr>
<td id="500MB.test"><input type="checkbox" name='check' value='500MB.test'
data-url="http://nl.altushost.com/500MB.test"/>File500MB</td>
</tr>
<tr>
<td id="1000mb.bin"><input type="checkbox" name='check' value='1000mb.bin'
data-url="http://speedtest.tele2.net/1GB.zip"/>File1GB</td>
</tr>
<button class="btn btn-primary compress">압축하기</button>
This is happening because you're not specifying an element at index 0 (or previous indexes). Thus, if you try and add an element into an empty array at index 1 (which happens when you check the second checkbox) then you're array needs to put in an empty value in at index 0 so that it can add an element into index 1.
A solution to this would be to use .push which appends items to the end of your arr_downloadName array:
let chekced_download = 0;
$(".compress").click(function() {
let arr_downloadName = [];
var checkElem = document.getElementsByName("check");
var size = checkElem.length;
for (var i = 0; i < size; i++) {
if (checkElem[i].checked == true) {
arr_downloadName.push(checkElem[i].value);
chekced_download++
}
}
console.log(arr_downloadName);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<tr>
<td id="10Mb.dat"><input type="checkbox" name='check' value='10Mb.dat' data-url="https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73751/world.topo.bathy.200407.3x21600x10800.jpg" />File10MB
</td>
</tr>
<tr>
<td id="100mb.bin"><input type="checkbox" name='check' value='100mb.bin' data-url="http://speedtest-ny.turnkeyinternet.net/100mb.bin" />File100MB
</td>
</tr>
<tr>
<td id="500MB.test"><input type="checkbox" name='check' value='500MB.test' data-url="http://nl.altushost.com/500MB.test" />File500MB</td>
</tr>
<tr>
<td id="1000mb.bin"><input type="checkbox" name='check' value='1000mb.bin' data-url="http://speedtest.tele2.net/1GB.zip" />File1GB</td>
</tr>
<button class="btn btn-primary compress">압축하기</button>
As a side note, while it isn't needed, I recommend that you add a variable such as checkElem which holds your collection of elements. Then, instead of having to re-query the DOM each time you can instead just reference your element list, which will improve overall performance.
Also, I noticed that you're not making use of jQuery to it's fullest. Instead, you can get all the elements with the name check which are checked using a different selector:
$("[name='check']:checked")
and then .map all the elements selected to an to their values:
$(".compress").click(function() {
let arr_downloadName = $("[name='check']:checked").toArray().map(function(e) {
return e.value;
})
console.log(arr_downloadName);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<tr>
<td id="10Mb.dat"><input type="checkbox" name='check' value='10Mb.dat' data-url="https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73751/world.topo.bathy.200407.3x21600x10800.jpg" />File10MB
</td>
</tr>
<tr>
<td id="100mb.bin"><input type="checkbox" name='check' value='100mb.bin' data-url="http://speedtest-ny.turnkeyinternet.net/100mb.bin" />File100MB
</td>
</tr>
<tr>
<td id="500MB.test"><input type="checkbox" name='check' value='500MB.test' data-url="http://nl.altushost.com/500MB.test" />File500MB</td>
</tr>
<tr>
<td id="1000mb.bin"><input type="checkbox" name='check' value='1000mb.bin' data-url="http://speedtest.tele2.net/1GB.zip" />File1GB</td>
</tr>
<button class="btn btn-primary compress">압축하기</button>
try
if (document.getElementsByName("check")[i].checked != null)
seems your code will work. you are using incorrect variable to put the values in array. Make minor correction. i.e use 'chekced_download' instead of i as below, to push the values in array
arr_downloadName[chekced_download] = document.getElementsByName("check")[i].value;
Checked is a very sneaky HTML attribute
where if checked looks like
<input checked />
<input checked="checked" />
and produces true result
where if NOT checked looks like
<input />
which produces NULL - because there is no checked attribute. So check for the checked check. McCheck Check!
.checked != null
Hence you getting empty value.

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 clone a <tr> in a table with Javascript

I want to duplicate the second <tr> everytime I click button add, as it shows in here, I mean I want to whenever I click on the button add a new <tr> will be added that do the same thing as the previous one.
<form id="frm1" action="Calculate.html">
<table id= "myTable">
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
</tr>
<tr id= "rowToClone">
<td>
<select id= "products">
<option value="80">Product-A</option>
<option value="80">Product-B</option>
<option value="80">Product-C</option>
<option value="80">Product-D</option>
<option value="16">Product-E</option>
</select>
</td>
<td><input type="number" id="ndc" placeholder=""></td>
<td><p id="ndpc"></p></td>
<td><p id="pu"></p></td>
<td><p id="ptpp"></p></td>
</tr>
</table>
<input type="button" onclick="Calculate()" value="calculate">
<input type="button" onclick="AddSelect()" value="Add">
I want it to do the same whole thing, I tried but never got successful the second part I am stuck to
first part:
function Calculate() {
var e = document.getElementById("products");
var productValue = e.options[e.selectedIndex].value;
document.getElementById("ndpc").innerHTML = productValue;
document.getElementById("ndpc").value = productValue;
if (e.selectedIndex === 0){
document.getElementById("pu").value = 21.2;
}
else if (e.selectedIndex === 1) {
document.getElementById("pu").value = 25.7;
}
else if (e.selectedIndex === 2 || e.selectedIndex === 3 ) {
document.getElementById("pu").value = 14;
}
else {
document.getElementById("pu").value = 6;
}
var pu = document.getElementById("pu").value;
document.getElementById("pu").innerHTML = pu;
var ndc = document.getElementById("ndc").value;
var ndpc = document.getElementById("ndpc").value;
var Result = ndc * ndpc * pu;
document.getElementById("ptpp").innerHTML = Result;
};
the second part that I want to solve:
function AddSelect(){
var row = document.getElementbyId("rowToClone");
var table = document.getElementById("myTable");
var clone = row.cloneNode(true);
clone.id = "New";
function createRow() {
//I don't know what to do.
} };
I am new to Javascript obviously, please help me.
When using methods such as cloneNode(), or createElement() you'll need to append the new node to the DOM or it'll just float around aimlessly. Also, when cloning a node, keep in mind that if it and/or its children have any #ids, you'll end up having duplicated #ids which is super invalid. You should either change the #ids on all clones or do away with #ids on cloned nodes and use classes, tags, attributes, etc. instead.
In this demo, I replaced the form controls' #ids with name attribute since that's all you need to have in order to submit values from a <form> to a server (that and a <input type='submit'> button of course).
Demo
function addSelect() {
var T = document.getElementById('xTable');
var R = document.querySelectorAll('tbody .row')[0];
var C = R.cloneNode(true);
T.appendChild(C);
}
<form id="frm1" action="Calculate.html">
<table id="xTable">
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
</tr>
</thead>
<tr class="row">
<td>
<select name="products">
<option value="80">Product-A</option>
<option value="80">Product-B</option>
<option value="80">Product-C</option>
<option value="80">Product-D</option>
<option value="16">Product-E</option>
</select>
</td>
<td><input type="number" name="ndc" placeholder=""></td>
<td>
<p id="ndpc"></p>
</td>
<td>
<p id="pu"></p>
</td>
<td>
<p id="ptpp"></p>
</td>
</tr>
</table>
<input type="button" onclick="addSelect()" value="Add">
</form>

Select specific table cell in JavaScript

I have a HTML like this:
<table id="laboral">
<tr>
<td><input type="text" name="start"/></td>
<td><input type="text" name="end"/></td>
<td><textarea name="desc"></textarea></td>
<td><button type="button" onclick="saveValues(this);createRow('laboral')"> + </button></td>
</tr>
</table>
What I want is to save the values in the three cells (2 inputs and 1 textarea).
The button creates another row just like the first, with the same inputs and names. The problem is that I don't know how to access THIS row, I mean, the row who owns the button.
I tried with this.parentNode.parentNode but didn't work.
Try this
<table id="laboral">
<tr>
<td><input type="text" name="start"/></td>
<td><input type="text" name="end"/></td>
<td><textarea name="desc"></textarea></td>
<td><button type="button" onclick="saveValues(this)"> + </button></td>
</tr>
</table>
var inputVals = [];
function saveValues(elm) {
// button td tr tbody table
var table = elm.parentNode.parentNode.parentNode.parentNode;
// iterating through the first row cells
for (var i = 0; i<table.rows[0].cells.length-1; i++) {
// the current cell
var cell = table.rows[0].cells[i];
// pushing the input elm's value into the array
inputVals.push(cell.childNodes[0].value);
// retrieving the pushed value
alert(inputVals[i]);
}
}
Fiddle example
You can modify the code.
You're passing a reference to the button into saveValues, so within saveValues the first argument will refer to the button. Let's call that argument btn. btn.parentNode will be the td containing the button, and `btn.parentNode.parentNode will be the tr containing that td. So:
function saveValues(btn) {
var tr = btn.parentNode.parentNode;
// Work with `childNodes` and the `childNodes` of those children to get the values
}

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.

Categories