I am creating a form and I have a field set for client information and the ability to add another field set for another client if needed.
As of now the additional field sets' field id adds by 1 which is good, but I would like for each of the fields in the field set to add by 1 as well.
var _counter = 0;
function Add() {
_counter++;
var oClone = document.getElementById("client1").cloneNode(true);
oClone.id += (_counter + "");
document.getElementById("placehere").appendChild(oClone);
Here's a page that clones and increments the fieldset as well as any children elements within the set. It's assuming that both fieldset and children inputs have a numeric suffix. i.e. fieldset1 and textfield2, etc.
Cheers.
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
// store a reference to the last clone so I can increment off that.
window.lastClone = null;
function incrementId(id) {
// regexp is looking for text with a number suffix. adjust accordingly.
var numberSuffixRegExp = /(.*?)(\d*)$/;
var regExpMatch = numberSuffixRegExp.exec(id);
// assuming a match will be made here, and position 1 and 2 are populated.
var prefix = regExpMatch[1];
var counter = parseInt(regExpMatch[2]);
counter++;
return prefix + counter;
}
function cloneFieldSet() {
if (!window.lastClone) {
window.lastClone = 'fieldset1';
}
var newFieldSet = document.getElementById(lastClone).cloneNode(true);
newFieldSet.id = incrementId(newFieldSet.id);
var tagNames = ['input', 'select', 'textarea']; // insert other tag names here
var elements = [];
for (var i in tagNames) {
// find all fields for each tag name.
var fields = newFieldSet.getElementsByTagName(tagNames[i]);
for(var k = 0; k < fields.length; k++){
elements.push(fields[k]);
}
}
for (var j in elements) {
// increment the id for each child element
elements[j].id = incrementId(elements[j].id);
}
document.getElementById("placehere").appendChild(newFieldSet);
window.lastClone = newFieldSet.id;
}
</script>
</head>
<body>
<input type='button' value='Clone' onclick='cloneFieldSet()'/><br/>
<fieldset id='fieldset1'>
<table>
<tr>
<td>Label One:</td>
<td><input type='text' id='fieldOne1'/></td>
</tr>
<tr>
<td>Label Two:</td>
<td><input type='text' id='fieldTwo1'/></td>
</tr>
<tr>
<td>Label Three:</td>
<td><select id='selectOne1'>
<option>Some Value</option>
</select></td>
</tr>
</table>
</fieldset>
<div id='placehere' style='margin:10px 0; border:1px solid black'>
</div>
</body>
</html>
Try This : It only adds an updated id to user input form elements.
If you want to updated all child elements in the fieldset, remove the if statement :)
var _counter = 0, _fcounter = 0;
function add(){
var i, j,
oClone = document.getElementById("client1").cloneNode(true),
fldTypes = "INPUT SELECT TEXTAREA CHECKBOX RADIO",
fields = oClone.children;
_counter++;
oClone.id += (_counter + "");
for(i=0, j= fields.length; i<j; i++){
if(fldTypes.indexOf(fields[i].nodeName) > -1){ //checks for user input form elements
_fcounter ++;
fields[i].id += (_fcounter + "");
}
}
document.getElementById("placehere").appendChild(oClone);
return oClone;
}
See Example: http://jsfiddle.net/yfn6u/8/
Related
I am using javascript to clone a row then renaming the element id's and incrementing one of the values by 1. This is not the actual code I'm working on but a generic example that shows the problem.
It is appending everything to the top of my row instead of below it
It increments once or twice then stops
The output I'm getting is:
10022018
10032018
10032018
10032018
10032018
10012018
What I'm expecting is:
10012018
10022018
10042018
10052018
10062018
10072018
<table id = "myTable">
<tr id="myRow">
<td>First cell <input type="text" id = "input" value = "10012018"></td>
</tr>
</table><br>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction() {
var i;
for(i=0; i<5;i++){
var row=document.getElementById("myRow");
var cln = row.cloneNode(true);
row.id = "rows" + i;
var inpa = document.getElementById("input");
inpa.id = "input" + i;
var a = parseFloat(document.getElementById("input0").value);
inpa.value = (a + 10000);
document.getElementById("myTable").appendChild(cln);
}
}
</script>
Edit
Robin Zigmond added that input0 was the culprit and not incrementing (corrected but I failed to explain).
var a = parseFloat(document.getElementById("input0").value); // Should be "input"
inpa.value = (a + (10000)); // Needs increment ...a + (10000 * i));
My explanation refers to this assignment to row.
row.id = "rows" + i; /* This assigns a new #id to the original not a clone
-- changed to `cln.id` */
When using a for loop leverage the incremental variable. When the clone was created, your references were still pointing to the original and it wasn't being used to increment anything so that's why it was just copying and not progressing.
Demo
Details commented in demo
<table id="xTable">
<tr id="xRow">
<td>First cell <input type="text" id="input" value="10012018"></td>
</tr>
</table><br>
<button onclick="xFunction()">Try it</button>
<script>
function xFunction() {
// In for loops declare i with let inside loop
// Start with 1 instead of 0 because you cloned the increment starting at 1000
for (let i = 1; i < 5; i++) {
var row = document.getElementById("xRow");
var cln = row.cloneNode(true);
// You are dealing with the clone not the original anymore
// Use i form increments
cln.id = "rows" + i;
// Target the clone specifically
// Use querySelector() to get #id, .class, or <tag>
var inpa = cln.querySelector("input");
// Once again var i to increment
inpa.id = "input" + i;
var a = parseFloat(document.getElementById("input").value);
// Remember i to increment but this is a little trickier
inpa.value = (a + (10000 * i));
document.getElementById("xTable").appendChild(cln);
}
}
</script>
Id's must be unique. Apply class to tr and input instead.
A generic solution
// n -> How many?
// start -> Start value
// index -> Index of value that should be incremented
// id -> Table id
function addRows(n, start, index, id) {
var table = document.getElementById(id);
for (var i = 2; i <= n + 1; i += 1) {
var arr = start.split("");
arr[index] = i.toString();
var incremented = arr.join("");
var tr = table.insertRow(-1);
tr.className = "row-" + i;
var cell = tr.insertCell(-1);
cell.textContent = "Cell ";
var span = document.createElement("span");
span.textContent = i + ": ";
var input = document.createElement("input");
input.className = "input-" + i;
input.value = incremented;
cell.appendChild(span);
cell.appendChild(input);
}
}
<table id="myTable">
<tr class="row-1">
<td>Cell <span>1: </span><input type="text" class="input-1" value="10012018"></td>
</tr>
</table><br>
<button onclick="addRows(5, '10012018', 3, 'myTable')">Try it</button>
<hr>
<table id="mySecondTable">
<tr class="row-1">
<td>Cell <span>1: </span><input type="text" class="input-1" value="14444"></td>
</tr>
</table><br>
<button onclick="addRows(8, '14444', 0, 'mySecondTable')">Try it</button>
I'm pretty junior, so I'm unsure on if I worded the question properly.
I'm looking to create a textbox in HTML where the user can input the amount of columns and rows for the table. From there I need to use Javascript/Jquery to create the table when the button is clicked.
So far I have been able to create the text boxes. I capture the inputed numbers into variables, and created two for loops.
It doesn't work... :/
<body>
Set Rows:<br>
<input type="text" id="setRows">
<br>
Set Columns:<br>
<input type="text" id="setColumns">
<button type='button' onclick='myForm()'>Create Table</button>
<p id = "demo1"></p>
<p id = "demo2"></p>
</body>
function myForm()
{
var setRows = document.getElementById("setRows").value;
//document.getElementById("demo1").innerHTML = setRows;
var setColumns = document.getElementById("setColumns").value;
//document.getElementById("demo2").innerHTML = setColumns;
}
$(document).ready(function()
{
$("button").click(function()
{
$("<table></table>").insertAfter("p:last");
for (i = 0; i < setRows; i++)
{
$("<tr></tr>").appendTo("table");
}
for (i = 0; i < setColumns; i++)
{
$("<td>column</td>").appendTo("tr");
}
});
});
The main problem is that you're setting the variables setRows and setColumns in a different function from the one that uses them. You should do everything in one function -- either bind it with the onclick attribute or with $("button").click() -- rather than splitting it into separate functions.
I also think it would be clearer to use nested loops to make it more obvious that you're adding cells to each row. appendTo() will automatically clone the object being appended if there are multiple targets, but this is an obscure feature (I'm very experienced with jQuery and didn't know about it until now) that isn't so obvious. It will also make the code easier to extend if you need to put different values in each cell (e.g. filling them from an array of data, or initializing with something like "row I col J").
function myForm() {
var setRows = $("#setRows").val();
var setColumns = $("#setColumns").val();
var table = $("<table>").insertAfter("p:last");
for (var i = 0; i < setRows; i++) {
var row = $("<tr>");
for (var j = 0; j < setColumns; j++) {
$("<td>column</td>").appendTo(row);
}
table.append(row);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Set Rows:<br>
<input type="text" id="setRows">
<br>
Set Columns:<br>
<input type="text" id="setColumns">
<button type='button' onclick='myForm()'>Create Table</button>
<p id = "demo1"></p>
<p id = "demo2"></p>
jsBin demo
<button type='button'>Create Table</button>
It's quite slow to append elements inside a for loop,
instead create a HTML representation of your table, and append it only once you're done generating it:
$("button").click(function(){
var setRows = +$("#setRows").val(); // Value to Number using Unary +
var setColumns = +$("#setColumns").val();
// THE HTML STRING
var table = "<table>";
// OUTER FOR LOOP : ROWS
for (var i=0; i<setRows; i++){
// START THE TR
table += "<tr>";
// INNER FOR LOOP :: CELLS INSIDE THE TR
for (var j = 0; j < setColumns; j++) {
table += "<td>column</td>";
}
// CLOSE THE TR
table += "</tr>";
}
// CLOSE THE TABLE
table += "</table>";
// APPEND ONLY ONCE
$("p:last").after(table);
});
As you see above I've used a for loop inside another for loop cause:
<tr> <!-- OUTER FOR LOOP (rows) -->
<td>column</td><td>column</td> <!-- INNER FOR LOOP (cells) -->
</tr>
This would work:
$(document).ready(function(){
$("#myBtn").click(function(){
var setRows = $('#setRows').val(); // get your variables inside the click handler so they are available within the scope of your function
var setColumns = $('#setColumns').val();
var rows=[]; // create an array to hold the rows
for (var r = 0; r < setRows; r++){ // run a loop creating each row
var cols=[]; // create an array to hold the cells
for (var c = 0; c < setColumns; c++){// run a loop creating each cell
cols.push('<td>column</td>'); // push each cell into our array
}
rows.push('<tr>'+cols.join('')+'</tr>'); // join the cells array to create this row
}
$('<table>'+rows.join('')+'</table>').insertAfter("p:last"); // join all of the rows, wrap in a table tag, then add to page
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Set Rows:<br>
<input type="text" id="setRows" value="4"/>
<br>
Set Columns:<br>
<input type="text" id="setColumns" value="5"/>
<button type="button" id="myBtn" >Create Table</button>
<p id = "demo1"></p>
<p id = "demo2"></p>
You have to use a nested loop (as others have suggested).
Also when creating elements using jQuery - you don't have to specify both opening and closing tags - $("<elem />") works nicely..
Snippet:
$(function () {
var go = $("#go");
var cols = $("#columns");
var rows = $("#rows")
go.click(function () {
var numRows = rows.val();
var numCols = cols.val();
var table = $("<table />");
var head = $("<thead />");
var row = $("<tr />");
// build header
var headRow = row.clone();
for (var i = 0; i < numCols; i++) {
var th = $("<th />");
th.append(i);
headRow.append(th);
}
table.append(headRow);
// build table
for (var j = 0; j < numRows; j++) {
var addRow = row.clone();
for (var k = 0; k < numCols; k++) {
var cell = $('<td />');
cell.css({"border":"solid 2px teal"});
cell.append("<p>R:" + j + " |C:" + k + "</p>");
addRow.append(cell);
}
table.append(addRow);
}
$('body').append(table);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<label>Rows:</label>
<input id="rows" />
<label>Columns:</label>
<input id="columns" />
<button id="go">Go!</button>
Your variables are created in a function (setRows and setColumns), so they are not available outside of this function. Define them globally if you want the "myForm" function to remain (it's not needed though).
Check this quick example, keeping your code intact:
var setRows = 0;
var setColumns = 0;
function myForm() {
//setRows = document.getElementById("setRows").value;
setRows = $('#setRows').val();
//setColumns = document.getElementById("setColumns").value;
setColumns = $('#setColumns').val();
}
$(document).ready(function() {
$("button").click(function() {
$("<table></table>").insertAfter("p:last");
for (i = 0; i < setRows; i++) {
$("<tr></tr>").appendTo("table");
}
for (i = 0; i < setColumns; i++) {
$("<td>column</td>").appendTo("tr");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Set Rows:
<br>
<input type="text" id="setRows">
<br>Set Columns:
<br>
<input type="text" id="setColumns">
<button type='button' onclick='myForm();'>Create Table</button>
<p id="demo1"></p>
<p id="demo2"></p>
A few pointers going forward:
You can skip the "myForm" function, and instead put your variables just inside the ready-function.
You're also binding "button" to two things: to run myForm and to create your table. Removing the myForm-function, like stated above, obviously means you can remove the "onclick" event. But even if you keep the function, the call to "myForm" would be better placed inside the ready-function.
I am using a large dynamically created table. It is 2+ columns with the first column being text and the second+ being values in text input fields. When the page loads, the input boxes have a default value. I want to be able to save the value when I make changes in the text field.
When I use $("#ID_NAME").val(), I get whatever value the user entered. If I drill down to the input field by other means, .val() gives me the default value when the page loaded. The page doesn't actually use any ids, I just added one for debugging.
I've posted a jsfiddle showing the problem. http://jsfiddle.net/GdjKp/1/
HTML:
<fieldset>
<legend>test</legend>
<table id="menuSection">
<thead>
<tr>
<th>Id</th>
<th>field</th>
</tr>
</thead>
<tbody>
<tr id="row_1">
<td>description</td>
<td>
<input id="test_id" type="text" value="default value"></input>
</td>
</tr>
</tbody>
</table>
</fieldset>Chane text value and click
<input type="button" value="Go" onclick="run();"> the two elements found by jQuery will be in console.log() and the two values will pop up.
JS :
function run() {
var a = $("fieldset");
var b = $(a[0]).find("table > tbody > tr");
var c = $(b[0]).children();
var d = $(c[1].innerHTML);
var result_1 = $(c[1].innerHTML);
var result_2 = $("#test_id");
console.log(result_1);
console.log(result_2);
alert(result_1.val());
alert(result_2.val());
}
What is going on here?
[EDIT]
Here is the final working code
function save() {
var cols = $("fieldset:first > table > thead > tr > th");
var sections = $("fieldset");
var ret = {};
var sectionsTmp = {};
var translation = {};
for (var j=1; j < cols.length-1; j++) { //loop on language columns, skipping field names and delete columns (first and last columns)
var lang = cols[j].innerHTML;
sectionsTmp = {};
for (var i=0; i < sections.length; i++) { //loop on sections/fieldsets
var sectionName = $(sections[i]).children("legend")[0].innerHTML;
var translations = $(sections[i]).find("table > tbody > tr");
translation = {};
for (var k=0; k < translations.length; k++) { //loop on translations in a section
var translationId = translations[k].innerText.trim();
var translationText = $(translations[k]).children().eq(j).find('input').val();
translation[translationId] = translationText.replace(/'/g,''');
}
sectionsTmp[sectionName] = translation;
}
ret[lang] = sectionsTmp;
}
var url = '<?= $basePath?>/admin/save/item/translations/';
var form = $('<form accept-charset="UTF-8" action="' + url + '" method="post">' +
'<input type="text" name="translations" value=\'' + JSON.stringify(ret) + '\' />' +
'</form>');
$('body').append(form);
console.log(form);
form.submit();
}
You're not actually selecting the element in the case of result_1 - you're cloning it based on its html.
This line:
var result_1 = $(c[1].innerHTML);
is equivalent to this:
var result_1 = $('<input id="test_id" type="text" value="default value"></input>');
As you can see, result 1 has no relation to what's been typed into the input field - it's completely detached from the DOM.
I want to be able to click the button and have it copy this:
<tr id="1">
<td>
<input type="number" class="cue">
</td>
<td>
<input type="time">
</td>
<td>
<input type="text">
</td>
</tr>
And be able to change the id of the <tr> based on what is before it. I also want it to change the value of the number box based on the variable cueset.
When you press the button to add a row it calls add_row()
function add_row(rowCount)
{
for(i=0; i<rowCount; i++)
{
index = index + 1;
$('table').append( $('#1').prop('id', index));
}
}
What im not sure how to do is have it change the id, or the value of the number box.
I don't understand the use of rowCount and the for loop from your explanation, so here it is without them
function add_row()
{
var mostRecentTr = [].pop.call($("tr"));
var newNum = 1+$(mostRecentTr).attr("id");
var newTr = $(mostRecentTr).clone().attr("id", newNum);
newTr.find(".cue").val(newNum);
$("table").append(newTr);
}
var lastRow = jQuery('tr[id]').last();
var currCount = parseInt(lastRow.id);
var newRow = lastRow.clone()
newRow.id = currCount++;
lastRow.parent().append(newRow);
Though I'd suggest something a bit better like this:
var lastRow = jQuery('tr[counter]').last();
var currCount = parseInt(lastRow.attr('counter'));
var newRow = lastRow.clone()
newRow.attr('counter', currCount + 1).id = ('myRow' + currCount + 1);
lastRow.parent().append(newRow);
I have created dynamic elements using javascript. These elements are created when i input an int value based on the value i get the number of elements.
My problem is that if i change the int value more elements are added instead i just want to keep the number of elements which has been entered in the int field.
Please help
Javascript i use
<script type="text/javascript">
var inival = 0; // Initialise starting element number
// Call this function to add textbox
function addTextBox() {
for (var i = 1; i <= document.getElementById('unit').value; i++) {
if(document.getElementById("my"+i+"Div") != null){
var child = document.getElementById("my"+i+"Div");
alert(child);
var parent = document.getElementById("area");
alert(parent);
alert(i);
parent.removeChild(child);
}
var newArea = add_New_Element();
var htcontents = "Unit"+i+": <input type='text' name='synchunit"+i+"' id='unit"+i+"'/>";
document.getElementById(newArea).innerHTML = htcontents; // You can any other elements in place of 'htcontents'
}
}
function add_New_Element() {
inival = inival + 1; // Increment element number by 1
var ni = document.getElementById('area');
var newdiv = document.createElement('div'); // Create dynamic element
var divIdName = 'my' + inival + 'Div';
newdiv.setAttribute('id', divIdName);
ni.appendChild(newdiv);
return divIdName;
}
function removeElement(id){
var child = document.getElementById(id);
alert(child);
var parent = document.getElementById('area');
parent.removeChild(child);
return true;
}
</script>
The way i call it
<tr class="trlist1">
<td style="border:0;">
<input name="projectunit" id="unit" onblur="addTextBox();"/>
</td>
</tr>
<tr>
<td style="border:0;" align="center">
<div id='area'>
</div>
</td>
</tr>
I have solved it myself
just added
function addTextBox() {
document.getElementById("area").innerHTML = '';
for (var i = 1; i <= document.getElementById('unit').value; i++) {
var newArea = add_New_Element();
var htcontents = "Unit"+i+": <input type='text' name='synchunit"+i+"' id='unit"+i+"'/>";
document.getElementById(newArea).innerHTML = htcontents; // You can any other elements in place of 'htcontents'
}
}
document.getElementById("area").innerHTML = '';
this line just resets the div.