The Select Items in my code below works if I havent added a new row yet.
The items are fetched from a db using php mysql.
How Can I still make the select options in the children elements work like the parent element cloned. The select button works like its disabled in the children element
I want the children element to also have the room to select items
<script type="text/javascript">
function create_tr(table_id) {
let table_body = document.getElementById(table_id),
first_tr = table_body.firstElementChild
tr_clone = first_tr.cloneNode(true);
table_body.append(tr_clone);
clean_first_tr(table_body.firstElementChild);
}
function clean_first_tr(firstTr) {
let children = firstTr.children;
children = Array.isArray(children) ? children : Object.values(children);
children.forEach(x => {
if (x !== firstTr.lastElementChild) {
x.firstElementChild.value = '';
}
});
}
function remove_tr(This) {
if (This.closest('tbody').childElementCount == 1) {
alert("First Row Can't Be Deleted");
} else {
This.closest('tr').remove();
}
}
</script>
<div class="col-xl-8 col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Add Device Information</h3>
</div>
<div class="card-body">
<form id="" method="POST" autocomplete="off" novalidate="novalidate">
<table class="table border text-nowrap text-md-nowrap table-striped mb-0">
<thead>
<tr>
<th>Device Model</th>
<th>Serial No</th>
<th>
<button type="button" id="add" class=" btn text-success" onclick="create_tr('table_body')">
<i class="fe fe-plus-circle" id="add" style="font-size:1.6em;"></i>
</button>
</th>
</tr>
</thead>
<tbody class="field_wrapper" id="table_body">
<tr>
<td>
<select class="form-control form-select select2" data-bs-placeholder="Select" name="model[]" required="" id="model"> <?php
$readALL1 = "SELECT * FROM productmodels WHERE deleted = 0";
$displayAll1 = mysqli_query($conn,$readALL1);
while($rowFetchAll1 = mysqli_fetch_array($displayAll1)){
$modelName = $rowFetchAll1['modelName'];
$modelid = $rowFetchAll1['modelID'];
?> <option value="
<?=$modelid?>"> <?=$modelName?> </option> <?php } ?> </select>
</td>
<td>
<input type="" name="" class="form-control" placeholder="Serial No...">
<input type="text" name="addedBy[]" class="form-control" id="addedBy" value="
<?=$_SESSION['user_uniq_id']?>" hidden="">
<input type="text" name="client[]" class="form-control" value="
<?=$clientID?>" id="client" hidden="">
<input type="text" name="deviceID[]" class="form-control" value="
<?=time()?>" id="deviceID" hidden="">
</td>
<td>
<button type="button" id="add" class=" btn text-danger" onclick="remove_tr(this)">
<i class="fe fe-minus-circle" id="add" style="font-size:1.6em;"></i>
</button>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
As per the comment I made above, you have duplicate IDs so whenever you use document.getElementByID you are going to have issues if attempting to call an element that has it's ID duplicated.
Fo the delete buttons to work you can either assign the event handler explicitly when you make the clone of the entire table row or the preferred method is to use a delegated event handler that intercepts click events to the common parent ( the table is easy ) and then reacts accordingly. The following HTML is a modified version of the above - all IDs have been removed, some replaced with dataset attributes. The select menu simply has a basic statically written few options to illustrate the case.
// No element in the HTML now has an ID so there will be no duplicate IDs. To identify
// DOM elements a more useful set of selectors (querySelector & querySelectorAll) are
// very useful. The `event` can be used to begin DOM traversal to find elements of
// interest rather than rely upon a static ID or crudely constructed dynamic IDs, usually
// involving numbers.
document.querySelector('button[data-name="add"]').addEventListener('click', e => {
// from the event.target, find the parent table row and from that the table-body
let tbody = e.target.closest('table').querySelector('tbody');
// clone the first row from table-body and do some manipulations
let clone=tbody.firstElementChild.cloneNode(true);
clone.querySelector('button[data-name="del"]').hidden=false;
clone.querySelectorAll('input, select').forEach(n=>{
n.value='';
});
// add the new row - no IDS anywhere.
tbody.appendChild(clone);
});
// Delegated Event Listener. This is bound to the table and monitors `click` events
// but processes only those events originating from the specified elements (button & i)
// - newly added elements are not registered in the DOM when the page loads initially
// which is why a delegated listener is used.
document.querySelector('form table#dyntbl').addEventListener('click', e => {
e.stopPropagation();
// only process clicks from either a button with dataset.name='del' or it's child i
if (e.target != e.currentTarget && (e.target.dataset.name == 'del' || e.target.parentNode.dataset.name == 'del')) {
// identify the table-body as before
let tbody = e.target.closest('table').querySelector('tbody');
// remove table row unless it is the 1st one otherwise things break.
if( tbody.childNodes.length > 3 ) tbody.removeChild(e.target.closest('tr') )
}
});
<div class='col-xl-8 col-md-12'>
<div class='card'>
<div class='card-header'>
<h3 class='card-title'>Add Device Information</h3>
</div>
<div class='card-body'>
<form method='POST' autocomplete='off' novalidate='novalidate'>
<table id='dyntbl' class='table border text-nowrap text-md-nowrap table-striped mb-0'>
<thead>
<tr>
<th>Device Model</th>
<th>Serial No</th>
<th>
<button type='button' data-name='add' class=' btn text-success'>
<i class='fe fe-plus-circle' data-id='add' style='font-size:1.6em;'>#Add#</i>
</button>
</th>
</tr>
</thead>
<tbody class='field_wrapper'>
<tr>
<td>
<select class='form-control form-select select2' data-bs-placeholder='Select' name='model[]' required>
<option>A
<option>B
<option>C
</select>
</td>
<td>
<input type='text' name='serial[]' class='form-control' placeholder='Serial No...' />
<input type='text' name='addedBy[]' class='form-control' hidden />
<input type='text' name='client[]' class='form-control' hidden />
<input type='text' name='deviceID[]' class='form-control' hidden />
</td>
<td>
<button type='button' data-name='del' class='btn text-danger' hidden>
<i class='fe fe-minus-circle' style='font-size:1.6em;'>#Delete#</i>
</button>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
Related
function disableField()
{
var Count = $('#dataTable tr').length;
if (Count == 2){
$("input").not('.DeleteButton').prop('disabled', false);
}else{
$("input").prop('disabled', false);
}
}
//--------------------------------------------------
var regex = /^([a-zA-Z0-9 _-]+)$/;
var cindex = 0;
var quicklink = '' ;
$(document).on('click','.Buttons', function(addrow) {
var count = $('table tr:last input:text').filter((_,el) => el.value.trim() == "").length;
if(count || !$('.id_100 option[value=code]').attr('selected','selected')){
alert("Please fill the current row");
return false;
}
var $tr = $('#dataTable tbody tr:last');
var $clone = $tr.clone(true);
cindex++;
$clone.find(':input').not('select').not('.DeleteButton').val('').attr('disabled', true);
$clone.attr('id', 'id'+(cindex) ); //update row id if required
//update ids of elements in row
$clone.find("*").each(function() {
var id = this.id || "";
if(id != ""){
var match = id.match(regex) || [];
if (match.length == 2) {
this.id = this.name + (cindex);
}
}
});
$tr.after($clone);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table cellspacing="0" cellpadding="0" border="0" id="mainbox" class="mainbox"><tr><td>
<div class="toppanel"><ul><li></li></ul></div>
<div class="abcd"> <!--mainbox middlepanel start-->
<table cellspacing="0" cellpadding="0" border="0" id="maintable" class="maintable">
<tr>
<td valign="top">
<div id="pageheadingpanel">
<div id="pageheading">Quick Link Widget Configuration</div>
<div id="pageheadingdate"><xsl:call-template name="formatted_date"/></div>
</div>
</td>
</tr>
<tr>
<td height="100%" valign="top">
<div class="y_scroll" id="contentarea">
<div class="contentarea"><!--contentarea start-->
<span id="box" class="box"> <!--rounded curve/border start-->
<div class="middlepanel"> <!--contentarea box middlepanel start-->
<div style="display:block" id="textBox1" >
<span id="box1" class="box">
<div class="toppanel"><ul><li></li></ul></div>
<div class="middlepanel">
<table border="0" cellspacing="1" cellpadding="1" id="dataTable" name="dataTable" class="graphtable">
<thead>
<tr>
<td class="headingalign" width="16%">Links</td>
<td class="headingalign" width="32%">Desciption</td>
<td class="headingalign" width="16%">Image</td>
<td class="headingalign" width="16%">URL</td>
<td class="headingalign" width="05%"></td>
</tr>
</thead>
<tbody>
<tr id="id0" class="vals" name="id0">
<td>
<div class="id_100">
<select type="select-one" id='fldsearch' class="objselect" name="fldsearch" onChange="disableField()" >
<option value="">Select</option>
<xsl:for-each select="values from local db">
<xsl:sort order="ascending" select="description"/>
<option value="{description}">
<xsl:value-of select="description"/>
</option>
</xsl:for-each>
</select>
</div> </td>
<td>
<input id="flddesc" name="flddesc" maxlength="500" disabled="true" class="objinputtext1" size="85" value="{//RESPONSE}" />
</td>
<td>
<input id="fldimg" name="fldimg" maxlength="50" disabled="true" class="objinputtext2" size="35" value="{//RESPONSE}" />
</td>
<td>
<input id="fldurl" name="fldurl" maxlength="15" disabled="true" class="objinputtext3" size="35" value="{//RESPONSE}" />
</td>
<td>
<input tabindex="6" value="Delete Row" disabled="true" class="DeleteButton" type="button" />
</td>
</tr>
</tbody>
</table>
<div class="buttonarea">
<ul>
<li><input tabindex="6" id="Button3" value="Add New Row" class="Buttons" name="Button3" type="button" /></li>
</ul>
</div>
I have a table with a drop-down column in it. Whenever i change the values of drop-down my corresponding fields get enabled. The problem i am getting is if i change the values of my drop-down of previous row the columns of current row also get enabled.Any help will be appreciated. Thanks.
Edit:I have added 'Add Row' function too in my code.
I have added some changes in your disableField function. Pass parameter(this) disableField(this) in that function on chnage event.
function disableField(elem)
{
var Count = $('#dataTable tr').length;
if (Count == 2){
$(elem).closest('tr').find("input").not('.DeleteButton').prop('disabled', false);
}
else{
$(elem).closest('tr').find("input").prop('disabled', false);
}}
//--------------------------------------------------
var regex = /^([a-zA-Z0-9 _-]+)$/;
var cindex = 0;
var quicklink = '' ;
$(document).on('click','.Buttons', function(addrow) {
var count = $('table tr:last input:text').filter((_,el) => el.value.trim() == "").length;
if(count || !$('.id_100 option[value=code]').attr('selected','selected')){
alert("Please fill the current row");
return false;
}
var $tr = $('#dataTable tbody tr:last');
var $clone = $tr.clone(true);
cindex++;
$clone.find(':input').not('select').attr('disabled', true);
$clone.attr('id', 'id'+(cindex) ); //update row id if required
//update ids of elements in row
$clone.find("*").each(function() {
var id = this.id || "";
if(id != ""){
var match = id.match(regex) || [];
if (match.length == 2) {
this.id = this.name + (cindex);
}
}
});
$tr.after($clone);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table cellspacing="0" cellpadding="0" border="0" id="mainbox" class="mainbox"><tr><td>
<div class="toppanel"><ul><li></li></ul></div>
<div class="abcd"> <!--mainbox middlepanel start-->
<table cellspacing="0" cellpadding="0" border="0" id="maintable" class="maintable">
<tr>
<td valign="top">
<div id="pageheadingpanel">
<div id="pageheading">Quick Link Widget Configuration</div>
<div id="pageheadingdate"><xsl:call-template name="formatted_date"/></div>
</div>
</td>
</tr>
<tr>
<td height="100%" valign="top">
<div class="y_scroll" id="contentarea">
<div class="contentarea"><!--contentarea start-->
<span id="box" class="box"> <!--rounded curve/border start-->
<div class="middlepanel"> <!--contentarea box middlepanel start-->
<div style="display:block" id="textBox1" >
<span id="box1" class="box">
<div class="toppanel"><ul><li></li></ul></div>
<div class="middlepanel">
<table border="0" cellspacing="1" cellpadding="1" id="dataTable" name="dataTable" class="graphtable">
<thead>
<tr>
<td class="headingalign" width="16%">Links</td>
<td class="headingalign" width="32%">Desciption</td>
<td class="headingalign" width="16%">Image</td>
<td class="headingalign" width="16%">URL</td>
<td class="headingalign" width="05%"></td>
</tr>
</thead>
<tbody>
<tr id="id0" class="vals" name="id0">
<td>
<div class="id_100">
<select type="select-one" id='fldsearch' class="objselect" name="fldsearch" onChange="disableField(this)" >
<option value="">Select</option>
<xsl:for-each select="values from local db">
<xsl:sort order="ascending" select="description"/>
<option value="{description}">
<xsl:value-of select="description"/>
</option>
</xsl:for-each>
</select>
</div> </td>
<td>
<input id="flddesc" name="flddesc" maxlength="500" disabled="true" class="objinputtext1" size="85" value="{//RESPONSE}" />
</td>
<td>
<input id="fldimg" name="fldimg" maxlength="50" disabled="true" class="objinputtext2" size="35" value="{//RESPONSE}" />
</td>
<td>
<input id="fldurl" name="fldurl" maxlength="15" disabled="true" class="objinputtext3" size="35" value="{//RESPONSE}" />
</td>
<td>
<input tabindex="6" value="Delete Row" disabled="true" class="DeleteButton" type="button" />
</td>
</tr>
</tbody>
</table>
<div class="buttonarea">
<ul>
<li><input tabindex="6" id="Button3" value="Add New Row" class="Buttons" name="Button3" type="button" /></li>
</ul>
</div>
All in all there is to much extraneous code so the following answer has different code yet can be applied to the clunky code provided in question. I recommend that your code be more streamlined like the following demo provided in this answer.
Here's some suggestions:
If you are using multiple form controls (ex. <button>, <input>, <textarea>, <select>, etc), wrap everything into a <form>
If you have multiple tags (aka elements) that the user can click, submit, reset, change, input, etc register the events to the <form>
In order to find the exact form control that was clicked, changed, etc. use the Event.target property to find it or this keyword and the Event.data parameter.
$('form selector').on('event type', Event.data, callback function)
The #id and [name] attributes are unnecessary unless you are using certain Web APIs such as HTMLFormControlsCollection or HTMLFormElement
Never use event attributes (ex onchange="callback()") when using jQuery. Use the proper jQuery method or .on() method.
// jQuery method
$(selector).click(callback)
// .on() method
$(selector).on('click', callback)
Minor details:
The [type] attribute does not apply to the <select> tag.
Use <th> instead of <td> within <thead>
[maxlength] of 500 is ridiculous. Use <textarea> instead of <input>
Details are commented in demo
/*
Register form.io to the 'submit', 'click', and 'change' events
Note the callback function does not have `()` suffixed because it would be
interpreted as: "run function now"
The callback function doesn't run immediately it runs when a registered event is triggered.
*/
$('.io').on('submit click change', eventHandler);
// Define the counter
let counter = 0;
// Always pass the Event Object when defining a callback function
function eventHandler(event) {
// The Event Object has several properties...
// Get the type of event triggered (ie submit, change, or click)
let eType = event.type;
/*
Get the origin element of event
if 'submit' target will be <form>
if 'click' target will be <button>
if 'change' target will be <select>
*/
let eNode = event.target;
// Pass the event type through a switch() function...
switch (eType) {
// if type is 'submit'...
case 'submit':
// Create a deep clone of the first row
let clone = $('.grid tr:first-child').clone(true, true);
// Add clone as the last child of the <tbody>
$('.grid').append(clone);
// On .each() elment with class '.data' found within the clone...
clone.find('.data').each(function(i) {
// disable it
this.disabled = true;
// remove its value
this.value = '';
});
// Increment the counter by 1
counter++;
// Dereference the clone and assign id as row+counter
clone[0].id = `row${counter}`;
/*
Prevent default behavior:
Reset <form>
Send data to a server
*/
event.preventDefault();
// Stop event from bubbling any further up the event chain
event.stopPropagation();
// ...otherwise skip this case and continue onto the next case
break;
// if type is 'click'...
case 'click':
// if the clicked element (ie <button>) has class: '.del'...
if ($(eNode).hasClass('del')) {
// Get the clicked <button>'s ancestor <tr>
let row = $(eNode).closest('tr');
// if that <tr> is NOT the first <tr>...
if (row.index() !== 0) {
// remove the <tr>
row.remove();
}
}
event.stopPropagation();
break;
// if type is 'change'...
case 'change':
// if changed element (ie <select>) class is '.type'...
if ($(eNode).hasClass('type')) {
// Get the changed <select>'s ancestor <tr>
let row = $(eNode).closest('tr');
// if changed <select>'s value is NOT "X" return true otherwise return false
let pick = eNode.value !== "X" ? true : false;
/*
On .each() element with class .data within the <tr>
disable the .data if <select>'s value is "X"
Otherwise enable the .data
and then remove the .data value
*/
row.find('.data').each(function(i) {
this.disabled = !pick;
this.value = '';
});
}
event.stopPropagation();
break;
default:
event.stopPropagation();
break;
}
}
:root {
font: 400 3vw/1.2 Arial
}
form {
width: max-content;
margin: 10px auto
}
table {
table-layout: fixed;
border-collapse: separate;
border-spacing: 4px;
width: 90vw
}
th:first-of-type {
width: 20%
}
th:nth-of-type(2) {
width: 35%
}
th:nth-of-type(3) {
width: 35%
}
th:last-of-type {
width: 10%
}
td {
padding: 0 8px
}
select,
textarea,
button {
display: block;
min-width: 97%;
min-height: 1.2rem;
font-size: initial;
}
select {
padding: 2px 0 2px 2px
}
textarea {
resize: vertical;
overflow-y: auto;
overflow-x: hidden
}
<form class='io'>
<table>
<thead>
<tr>
<th>Type</th>
<th>Desciption</th>
<th>Image/URL</th>
<th><button>➕</button></th>
</tr>
</thead>
<tbody class='grid'>
<tr>
<td>
<select class='type'>
<option value="X" default></option>
<option value="GDS">Guides</option>
<option value="PRO">Promos</option>
<option value="TEM">Templates</option>
<option value="VID">Videos</option>
</select>
</td>
<td><textarea class='desc data' rows='1' cols='20' disabled></textarea></td>
<td><textarea class='urls data' rows='1' cols='20' disabled></textarea></td>
<td><button class='del' type='button'>❌</button></td>
</tr>
</tbody>
</table>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I'm making an address book of a company's tech support contacts and the admin gets access to all addresses in a form of a table. In this table, he can add, delete and make changes to data in the same page.
I have set up the add and delete functions successfully, but I struggle a lot with the edit. I'm using node, express, mongodb and vanilla javascript.
I'm still a newbie in web developement and there is are words I may use wrong, so sorry in advance!
(Excuse my french, but most of the words mean the same in english.)
My HTML
<div>
<input id="edit" type="button" value="Editer" onclick="return edit()">
<input id="valider" type="hidden" value="Valider" onclick="return valider()">
</div>
<table id='myTable'>
<thead>
<tr class="header">
<th>Nom de l'entreprise</th>
<th>Téléphone 1</th>
<th>Téléphone 2</th>
<th>Mail</th>
</tr>
</thead>
<tbody>
<% companies.forEach(function(company){ %> //I loop through my db
<tr class="compName">
<td hidden id='_id' > <%= company._id %> </td>
<td> <input id="name" class="readonly" type="text" value=" <%= company.name %>" readonly style="border: none" onblur="change(this)"> </td>
<td> <input id="phone" class="readonly" type="text" value=" <%= company.phone %>" readonly style="border: none" onblur="change(this)"> </td>
<td> <input id="phone2" class="readonly" type="text" value=" <%= company.phone2 %>" readonly style="border: none" onblur="change(this)"> </td>
<td> <input id="mail" class="readonly" type="text" value=" <%= company.mail %>" readonly style="border: none" onblur="change(this)"> </td>
</tr>
<% }) %>
</tbody>
</table>
My Script
<script>
function edit() {
var editComp = document.getElementsByClassName("readonly");
var edit = document.getElementById('edit').type = 'hidden'; //get the edit button and hide it
var valider = document.getElementById('valider').type = 'button'; //then unhide the validate button so I can use it
for (var i = 0; i < editComp.length; i++) { //remove the readonly for each td so I can edit it
editComp[i].removeAttribute('readonly');
editComp[i].setAttribute("style", "border: 1px solid red;");
};
}
function valider() {
var editComp = document.getElementsByClassName("readonly");
var edit = document.getElementById('edit').type = 'button'; //unhide the edit button
var valider = document.getElementById('valider').type = 'hidden' //hide my validate button
for (var i = 0; i < editComp.length; i++) { //put back the readonly for each td so its uneditable
editComp[i].setAttribute('readonly', true);
editComp[i].setAttribute("style", "border: none;");
};
}
function change(element) { //when the input gets unfocused, I assume that's because changes happened
var setChanged = element.setAttribute("class", "readonly changed"); //I mark all changed element
/*I want to udapte my database with the changed elements
I was thing of getting the hidden company._id and the id of the changed element so I can update them specifically*/
}
</script>
So I was think of getting the col[0] of the changed row, which is the _id of my changed element, so I can target it for updating in my database, but I don't know how I should do it.
Thanks!
I have to clone my <tr> and I have list of checkbox like code below and when I add new row with list of checkbox and then I click on check box to show value in textbox field_resultsthe value not show only on first textbox not yet clone.
How when I add new tr and then when I click on which list of checkbox in which tr they will show value of my click in the same tr.
$("#add-new").on("click", function () {
$tr = $(this).closest("tr").next().clone(true);
$tr.insertAfter($(this).closest("tr"));
});
$(document).ready(function () {
$checks = $('#mych_box :checkbox');
$checks.on('change', function () {
var string = $checks.filter(":checked").map(function (i, v) {
return this.value;
}).get().join(",");
console.log(string);
$('#field_results').val(string);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<tr>
<td>
<button type="button" id="add-new">Add New</button>
</td>
</tr>
<tr>
<td>
<input type="text" id="field_results" name="field_results[]"/><br>
<div class="multiselect" style="height: 100px;width: auto;" id="mych_box">
<label>
<input type="checkbox" id="virt_software_chb1" name="virt_software[]" value="White"/>White
<input type="checkbox" id="virt_software_chb2" name="virt_software[]" value="Red"/>Red
<input type="checkbox" id="virt_software_chb3" name="virt_software[]" value="Blue"/>Blue
</label>
</div>
</td>
</tr>
As defined above use true in clone to bind default events and use class instead of id to group element
$(".virt_software_chb").on('change', function () {
var string = $(this).closest('td').find('.virt_software_chb').filter(":checked").map(function (i, v) {
return this.value;
}).get().join(",");
$(this).closest('td').find('.field_results').val(string);
});
$("#add-new").on("click", function () {
$tr = $(this).closest("tr").next().clone(true);
$tr.insertAfter($(this).closest("tr"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>
<button type="button" id="add-new">Add New</button>
</td>
</tr>
<tr>
<td>
<input type="text" class="field_results" name="field_results[]"/><br>
<div class="multiselect" style="height: 100px;width: auto;" id="mych_box">
<label>
<input type="checkbox" class="virt_software_chb" name="virt_software[]" value="White"/>White
<input type="checkbox" class="virt_software_chb" name="virt_software[]" value="Red"/>Red
<input type="checkbox" class="virt_software_chb" name="virt_software[]" value="White"/>White
</label>
</div>
</td>
</tr>
</table>
withDataAndEvents (default: false)
A Boolean indicating whether event handlers should be copied along with the elements. As of jQuery 1.4, element data will be copied as well. - clone()
Try passing in true and see what you get.
$tr = $(this).closest("tr").next().clone(true);
Below in the example, I want that each time when the add button is clicked to take the element inside the template div and append it to the landingzone class element. But at the same time I need the NEWID to change for the new element. Of course this is just an example, the table stuff can be a div or anything else.
the form:
<form method="post">
<input type="text" name="title">
<input type="text" name="number">
<table>
<thead>
<tr> <th>Parts</th> </tr>
</thead>
<tbody class="landingzone">
</tbody>
</table>
<input type="submit" value="Save">
<input type="button" name"add" class="add" value="Save">
</form>
the template:
<div class="template" style="display: hidden">
<tr id="NEWID">
<td>
<input type="text" name="part_NEWID">
</td>
</tr>
</div>
What would be the best way to accomplish this?
Here's an example for your need. The javascript will work without changing any html except in place of name"add" should be name="add"
What i have done here is i'm getting the id of the template tr and setting it with increment and also the input field name.
var $landingzone = $('.landingzone');
var $add = $('.add');
var desiredId = 'id';
$add.on('click', function() {
var $template = $('.template').find('tr');
var id = $template.attr('id');
var idArr = id.split('-');
if (!idArr[1]) {
id = desiredId + '-1';
} else {
id = desiredId + '-' + (parseInt(idArr[1]) + 1);
}
$template.attr('id', id);
$template.find('input').attr('name', 'part_'+id);
console.log('input id--->'+id, 'input name--->'+'part_'+id);
$landingzone.append($template.clone());
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form method="post">
<input type="text" name="title">
<input type="text" name="number">
<table>
<thead>
<tr>
<th>Parts</th>
</tr>
</thead>
<tbody class="landingzone">
</tbody>
</table>
<input type="submit" value="Save">
<input type="button" name="add" class="add" value="Add">
</form>
<table class="template" style="display: none">
<tr id="NEWID">
<td>
<input type="text" name="part_NEWID">
</td>
</tr>
</table>
Like #Andrea said in her comment, some more details would be appreciated ...
I think what you are after is:
const $template = $('.template').clone()
$template.attr('id', 'someId')
$template.find('input[name="part_NEWID"]').attr('name', 'part_someId')
$('.landingzone').append($template)
And if you need it in a function:
function appendTemplateToLandingZone (newId) {
const $template = $('.template').clone()
$template.attr('id', newId)
$template.find('input[name="part_NEWID"]').attr('name', 'part_' + newId)
$('.landingzone').append($template)
}
I haven't tested this, so it might need a slight adjustment. If you'll provide a basic jsbin I'll make it work there.
I have a dynamically created table with 4 text inputs and 1 drop down selection.
When the user clicks the Add button, a clone of the previous row is added to the table. That works as it should. what I'm trying to do is increase the Unit ID input by 1. For example first row is 1111T-01 when the add button is clicked I want the next row Unit ID to be 1111T-02. Thank you.
HTML CODE
<h2>Please fill in the information below</h2>
<form action="pmUnitCreate.php" method="post">
<p>Click the Add button to add a new row. Click the Delete button to Delete ALL rows.</p>
<input type="button" id="btnAdd" class="button-add" onClick="addRow('myTable')" value="Add"/>
<input type="button" id="btnDelete" class="button-delete" onClick="deleteRow('myTable')" value="Delete"/>
<br>
<table id="myTable" class="form">
<tr id="heading">
<th><b><font size="4">Job Number</font></b></th>
<th><b><font size="4">Job Code</font></b></th>
<th><b><font size="4">Unit ID</font></b></th>
<th><b><font size="4">Model Number</font></b></th>
<th><b><font size="4">Scope</font></b></th>
</tr>
<tr id="tableRow">
<td>
<input type="text" name="JobNumber[]" required>
</td>
<td>
<input type="text" name="JobCode[]" required>
</td>
<td>
<input type="text" name="UnitID[]" required>
</td>
<td>
<input type="text" name="ModelNumber[]" required>
</td>
<td>
<select id="Scope" name="Scope[]" required>
<option>100OA</option>
<option>BTank</option>
<option>WSEcon</option>
<option>NetPkg</option>
<option>CstmCtrl</option>
<option>CstmRef</option>
<option>CstmSM</option>
<option>CstmHV</option>
<option>CPCtrl</option>
<option>DesiHW</option>
<option>DigScroll</option>
<option>DFGas</option>
<option>DWall</option>
<option>MZ-DD</option>
<option>DPP</option>
<option>Encl</option>
<option>PlateHX</option>
<option>ERW</option>
<option>ERWModule</option>
<option>ERVMod</option>
<option>EvapBP</option>
<option>PreEvap</option>
<option>XP</option>
<option>Extend</option>
<option>FanWall</option>
<option>FillStat</option>
<option>FFilt</option>
<option>PFilt</option>
<option>CarbFilt</option>
<option>CustFilt</option>
<option>MGH(H)</option>
<option>GHeat</option>
<option>HighStatic</option>
<option>HGBP</option>
<option>HGRH</option>
<option>HPConv</option>
<option>GFHumid</option>
<option>TOHumid</option>
</select>
</td>
</tr>
</table>
JS CODE
<script>
function addRow() {
var row = document.getElementById("tableRow"); // find row to copy
var table = document.getElementById("myTable"); // find table to append to
var clone = row.cloneNode(true); // copy children too
//clone.id = "newID"; // change id or other attributes/contents
table.appendChild(clone); // add new row to end of table
}
function deleteRow() {
document.getElementById("myTable").deleteRow(-1);
}
</script>
jsfiddle
If the unit id is always xxxx-1 and the x is never a - this should do the work.
If the x can be a - let me know and I'll update the answer accordingly.
function incrementUnitId(unitId) {
var arr = unitId.split('-');
if (arr.length === 1) {return;} // The unit id is not valid;
var number = parseInt(arr[1]) + 1;
return arr[0] + '-' + (number < 10 ? 0 : '') + number;
}
function addRow() {
var row = document.getElementById("tableRow"); // find row to copy
var table = document.getElementById("myTable"); // find table to append to
var clone = row.cloneNode(true); // copy children too
row.id = "oldRow"; // We want to take the last value inserted
clone.cells[2].childNodes[1].value = incrementUnitId(clone.cells[2].childNodes[1].value)
table.appendChild(clone); // add new row to end of table
}
function deleteRow() {
document.getElementById("myTable").deleteRow(-1);
}
<h2>Please fill in the information below</h2>
<form action="pmUnitCreate.php" method="post">
<p>Click the Add button to add a new row. Click the Delete button to Delete ALL rows.</p>
<input type="button" id="btnAdd" class="button-add" onClick="addRow('myTable')" value="Add"/>
<input type="button" id="btnDelete" class="button-delete" onClick="deleteRow('myTable')" value="Delete"/>
<br>
<table id="myTable" class="form">
<tr id="heading">
<th><b><font size="4">Job Number</font></b></th>
<th><b><font size="4">Job Code</font></b></th>
<th><b><font size="4">Unit ID</font></b></th>
<th><b><font size="4">Model Number</font></b></th>
<th><b><font size="4">Scope</font></b></th>
</tr>
<tr id="tableRow">
<td>
<input type="text" name="JobNumber[]" required>
</td>
<td>
<input type="text" name="JobCode[]" required>
</td>
<td>
<input type="text" name="UnitID[]" required>
</td>
<td>
<input type="text" name="ModelNumber[]" required>
</td>
<td>
<select id="Scope" name="Scope[]" required>
<option>100OA</option>
<option>BTank</option>
<option>WSEcon</option>
<option>NetPkg</option>
<option>CstmCtrl</option>
<option>CstmRef</option>
<option>CstmSM</option>
<option>CstmHV</option>
<option>CPCtrl</option>
<option>DesiHW</option>
<option>DigScroll</option>
<option>DFGas</option>
<option>DWall</option>
<option>MZ-DD</option>
<option>DPP</option>
<option>Encl</option>
<option>PlateHX</option>
<option>ERW</option>
<option>ERWModule</option>
<option>ERVMod</option>
<option>EvapBP</option>
<option>PreEvap</option>
<option>XP</option>
<option>Extend</option>
<option>FanWall</option>
<option>FillStat</option>
<option>FFilt</option>
<option>PFilt</option>
<option>CarbFilt</option>
<option>CustFilt</option>
<option>MGH(H)</option>
<option>GHeat</option>
<option>HighStatic</option>
<option>HGBP</option>
<option>HGRH</option>
<option>HPConv</option>
<option>GFHumid</option>
<option>TOHumid</option>
</select>
</td>
</tr>
</table>