how to edit all the td's on tbody - javascript

so what im trying to do is to add the "change" functionality in my code, it works for only the first td but not any other, when i click the other td it automaticly edits the first one.
does anyone know why my code is only changing the td>name/td> and not the td>adress/td> or any other td>
html:
<form id="registrering">
<label>Navn: <input id="inpnavn" placeholder="Raahim Khan" type="text" required></label>
<label>Adresse: <input id="inpadresse" type="text" placeholder="Adresse 12" required></label>
<label>Mobilnummer: <input id="inpmobilnummer" placeholder="12345678" required></select></label>
<label>Kjønn:
<select id="inpkjønn" required>
<option value="" selected disabled hidden>Velg kjønn</option>
<option>Mann</option>
<option>Kvinne</option>
<option>intetkjønn</option>
</select>
</label>
<button type="submit">Send inn</button>
</form>
//showing the data on website
function hentruss(snapshot){
var pk = snapshot.key;
var nyruss = snapshot.val();
var russref = database.ref("russ/" + nyruss.russ);
russref.on("value", function(snapshotruss){
var russobj = snapshotruss.val();
txttabell.innerHTML += `
<tr id="${pk}">
<td><label class="russlabel" onclick="edit('${pk}')">${nyruss.navn}</label><input type="text" class="editItem" style="display:none"></td>
<td><label class="russlabel" onclick="edit('${pk}')">${nyruss.adresse}</label><input type="text" class="editItem" style="display:none"></td>
<td>${nyruss.mobilnummer}</td>
<td>${nyruss.kjønn}</td>
<td><label class="delete" onclick="slett('${pk}')"><button>Slett</button></label></td>
</tr>
`;
});
}
//update the name,adress etc by clicking the element.
function edit(pk) {
var russen = russ.child(pk);
var label = document.querySelector(`#${pk} .russlabel`);
label.style.display = "none";
var tekst = label.innerText;
var inputfelt = document.querySelector(`#${pk} .editItem`);
inputfelt.style.display = "block";
inputfelt.value = tekst;
inputfelt.focus();
inputfelt.onblur = function() {
inputfelt.style.display = "none";
label.style.display = "block";
};
inputfelt.onchange = function() {
russen.update( {tekst: inputfelt.value} )
inputfelt.style.display = "none";
label.style.display = "block";
label.innerText = inputfelt.value;
};
}

It's a little hard to give an exact solution as the code snippets you have shared have a lot of calls to function whose context is not clear.. I have done my best to illustrate how you can do what you are trying to.. Maybe this will help get started in the right direction:
function handleSubmit(form) {
// Simulate creation of item using a form
var name = form.name.value;
var mobile = form.mobile.value;
// Generate random pk for demonstration
var pk = `pk${+new Date()}`;
var tableBody = document.querySelector('table tbody');
tableBody.innerHTML += ` <tr>
<td>
<label class="russlabel" onclick="edit(this)" data-pk="1" data-field="name">${name}</label>
<input class="editItem" style="display:none;" />
</td>
<td>
<label class="russlabel" onclick="edit(this)" data-pk="1" data-field="mobile">${mobile}</label>
<input class="editItem" style="display:none;" />
</td>
</tr>`;
return false;
}
function edit(label) {
var pk = label.dataset.pk;
var field = label.dataset.field;
var input = label.parentElement.children[1]; // Use label.parent.querySelector('input') if DOM is more complex
label.style = 'display:none;';
input.style = 'disply:block;';
input.focus();
input.value = label.innerHTML;
input.onchange = function() {
// pk and field are available here
// to Update DB state?? not sure how this code works
//var russen = russ.child(pk);
//russen.update( {tekst: inputfelt.value} )
}
input.onblur = function() {
label.innerHTML = input.value;
label.style = 'display:block;';
input.style = 'display:none;';
}
}
td {
padding: 0.5rem 0;
border-bottom: 1px solid black;
}
form {
margin: 1rem auto;
}
<form id="entry" onsubmit="return handleSubmit(this);">
<input name="name" placeholder="Name" />
<input name="mobile" placeholder="mobile" />
<input type="submit" value="Add Entry" />
</form>
<table>
<thead>
<tr>
<th>Name</th>
<th>Mobile</th>
</thead>
<tbody>
<tr>
<td>
<label class="russlabel" onclick="edit(this)" data-pk="1" data-field="name">Tom</label>
<input class="editItem" style="display:none;" />
</td>
<td>
<label class="russlabel" onclick="edit(this)" data-pk="1" data-field="mobile">1234</label>
<input class="editItem" style="display:none;" />
</td>
</tr>
</tbody>
</table>
Some notes:
It may be a good idea to read up on/ brush up on JS Events Here and refactor out the in line event handlers - these make your code hard to maintain, read, reason about, debug and are generally a bad idea.
Same goes for inline styles - avoid them. Try using classes with supporting styles in a stylesheet instead. (For example, on clicking a label, we could add an active class to the td element which in turn automatically hides the label and shows the input.
It's bad practice to reassign listeners to the inputs each time the label is clicked. The same functionality can be handled in a simpler and more graceful manner by using something like Event Delegation

Related

Exclude from a for() in javascript, an Array of 'ElementByName' ending with

First of all, sorry for the post's title.
I am trying to get references from these questions:
GetElementsByName with array like name
getElementsByName: control by last partial name
How can I select an element by ID with jQuery using regex?
And more or less I understood how to proceed.
I am using this code to check all the <input> and prevent the form from being submitted if any of the field is empty:
$('form[id="insertForm"]').on("submit", function (e) {
var form = document.getElementById("insertPanel");
var inp = form.getElementsByTagName('input');
for(var i in inp){
if(inp[i].type == "text"){
if(inp[i].value == ""){
inp[i].focus();
e.preventDefault();
$("#formAlert").show(400);
break;
}
}
}
});
The "problem", is that I was asked to add an exception, and one of these <input> can be empty.
The form is similar to this, what I post here is simplified:
<form id="insertForm" >
<div id="insertPanel">
<input type="text" name="FOO1" id="FOO1" />
<input type="text" name="FOO2" id="FOO2" />
<input type="text" name="FOO3" id="FOO3" />
<input type="text" name="FOO4" id="FOO4" />
<button type="submit" name="submit" value="Submit" >Send</button>
<table id="tab_logic">
<thead>
<tr>
<th>Bar1</th>
<th>Bar2</th>
<th>Bar3</th>
<th>Bar4</th>
<th>Bar5</th>
<th>Bar6</th>
<th>Bar7</th>
<th>Bar8</th>
<th>Bar9</th>
</tr>
</thead>
<tbody>
<tr id='addr_100'>
<td>
<input type="text" name='prefs[0][FooBar_A]' />
</td>
<td>
<input type="text" name='prefs[0][FooBar_B]' />
</td>
<td>
<input type="text" name='prefs[0][FooBar_C]' />
</td>
<td>
<input type="text" name='prefs[0][FooBar_D]' />
</td>
<td>
<input type="text" name='prefs[0][FooBar_E]' />
</td>
<td>
<input type="text" name='prefs[0][FooBar_F]' />
</td>
<td>
<input type="text" name='prefs[0][FooBar_G]' />
</td>
<td>
<input type="text" name='prefs[0][FooBar_H]'/>
</td>
<td>
<input type="text" name='prefs[0][FooBar_I]' />
</td>
</tr>
<tr id='addr_101'/>
</tbody>
</table>
<a id="add_row">Add Row</a>
<a id='delete_row'>Delete Row</a>
</form>
I removed all the CSS. Kept is really simple.
I was asked to NOT check the input <input type="text" name='prefs[0][FooBar_G]' />
As you can see, it is an array, at every "add row" click, there is a jquery that adds a new row with name='prefs[1][FooBar_A]' and so on.
I tried to work on the for():
$('form[id="insertForm"]').on("submit", function (e) {
var form = document.getElementById("insertPanel");
var inp = form.getElementsByTagName('input');
var SKIP = form.querySelectorAll('input[name$="FooBar_G]"]');
for(var i in inp){
if(inp[i].type == "text"){
if(inp[i].value == ""){
if (SKIP){ console.log("Element " + SKIP.innerText + " found. "); continue; }
inp[i].focus();
e.preventDefault();
$("#formAlert").show(400);
break;
}
}
}
});
And many other versions.. failing.
Anyone knows how to make this working?
let inputs = [...document.querySelectorAll('input')]
let reg = new RegExp('FOO[0-9]', 'g')
let filtered = inputs.filter(({ name }) => name.match(reg))
console.log(filtered)
<input type="text" name="FOO1" id="FOO1" />
<input type="text" name="FOO2" id="FOO2" />
<input type="text" name="FOO3" id="FOO3" />
<input type="text" name="FOO4" id="FOO4" />
<input type="text" name='prefs[0][FooBar_A]' />
<input type="text" name='prefs[0][FooBar_B]' />
<input type="text" name='prefs[0][FooBar_C]' />
<input type="text" name='prefs[0][FooBar_D]' />
$('form[id="insertForm"]').on("submit", function (e) {
var form = document.getElementById("insertPanel")
var reg = new RegExp('FOO[0-9]', 'g')
var inputs = [...document.querySelectorAll('input')].filter(({name}) => name.match(reg))
inputs.forEach((inp, i) => {
if(inp[i].type === "text" && inp[i].value === ""){
inp[i].focus();
$("#formAlert").show(400);
}
})
});
Use querySelectorAll to exclude that input (and to shorten your code). Specifically, the :not([name$=FooBar_G\\]]) selector to exclude the one you want to keep out. It can also be used to specify the text inputs.
You can simply the selector using the *= contains selector if you know that there will not be false positives. :not([name*=FooBar_G])
$('form#insertForm').on("submit", function(event) {
var inputs = this.querySelectorAll("#insertPanel input[type=text]:not([name$=FooBar_G\\]])");
for (var i = 0; i < inputs.length; i++) {
if (!inputs[i].value) {
inputs[i].focus();
event.preventDefault()
$("#formAlert").show(400);
break;
}
}
});
And to do it in a more modern way, I'd do this:
document.querySelector('form#insertForm').addEventListener("submit", function(event) {
const inp = Array.from(
this.querySelectorAll("#insertPanel input[type=text]:not([name$=FooBar_G\\]])")
).find(inp => !inp.value);
if (inp) {
inp.focus();
event.preventDefault()
$("#formAlert").show(400);
}
});
Some things:
1) if(SKIP) will always enter the branch as objects are truthy. You need compare sth (===)
2) If you already include such a heavy library like jquery you should use it everywhere to make it worth it
$('form[id="insertForm"]').on("submit", function (e) {
const inputs = $("#insertPanel > input").toArray();
const skip = $('input[name$="FooBar_G]"]')[0];
for(const input of inputs){
if(input === skip) continue;
if(!input.value){
input.focus();
e.preventDefault();
$("#formAlert").show(400);
break;
}
}
});

Dblclick listener firing only once in my code

I am new to Javascript and I developed following code which works only once.
function display(arr) {
$(".tbl tbody").empty();
for (i = 0; i < arr.length; i++) {
$(".tbl tbody").append('<tr class="tblrow" id = "'+i+'"> <td><input id="editInput" type="text"/>'+arr[i].Empid+'</td><td>'+arr[i].name+'</td><td>'
+arr[i].pd+'</td><td>'+arr[i].unplannedleaves+'</td><td>'+arr[i].response_time+'</td><td class = "tt"><button class="delbtn" id ="btn'+i+'">Delete</button></td></tr>');
$("td").css("text-align", "center");
$("td").css("border", "1px solid black");
$(".tt").css("border", "none");
$(".tbl").css("border", "none");
$(".delbtn").css("display", "none");
}
}
$("tr").on('dblclick', function() {
var s = this.id;
$("#btn" + s).css("display", "block");
});
$(".delbtn").click(function() {
var s = this.id;
var k = s.slice(3);
arr.splice(k, 1);
display(arr);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="addelem">
<table class="tbl1">
<tr>
<td>
<input id="empid" type="text" placeholder="EmpId">
</td>
<td>
<input id="name" type="text" placeholder="Name">
</td>
<td>
<input id="pd" type="number" placeholder="Pds Delivered">
</td>
<td>
<input id="unp" type="number" placeholder="Unplanned leaves">
</td>
<td>
<input id="rsp" type="number" placeholder="Response Time">
</td>
</tr>
</table>
<button id="submit">Submit</button>
<button id="cancel">Cancel</button>
</div>
After my table gets displayed usingdisplay method. The first time I dblclick a row it works as expected and displays the delete button. I click delete the row gets deleted and the table is re-rendered. However, after this the row is no more dbl-clickable. I tried debugging but the control won't even go in the dblclick listener.
Can someone explain why is it so. Whats going wrong in here?
Bind your tr element like this:
$(document).on('dblclick', "tr", function() {
var s = this.id;
$("#btn" + s).css("display", "block");
});
It will dynamically subscribe any new tr with your dblclick event

Issue Cloning Form Fields Within Table with Javascript

In the code below it works great to clone the table, but it doesn't go deep enough to rename the inputs of each form field in the table. For example Attendee1, Attendee2, Attendee3 etc.
Is there a way instead of just grabbing NewEl.children a way to just find all the input elements within the table then rename them?
I am not trying to add a row, I need to clone the entire table.
Any help you all out there in cyberland can give will be greatly appreciated.
<form name="EditRoster" method="post" action="DoRoster.php">
<table id="RosterTbl" cellspacing="0" cellpadding="2">
<tr style="text-align:left;vertical-align:top;">
<td><b>Name</b>:</td>
<td>
<input type="text" name="Attendee" value="" size="25" onclick="alert(this.name)">
</td>
<td><b>Paid</b>:</td>
<td>
<input type="checkbox" name="Paid" value="Yes" size="25">
</td>
</tr>
<tr style="text-align:left;vertical-align:top;">
<td><b>Email</b>:</td>
<td>
<input type="text" name="Email" value="" size="25">
</td>
<td><b>Paid When</b>:</td>
<td>
<input type="text" name="PaidWhen" value="" size="10">
</td>
</tr>
</table>
<div style="padding:5px;">
<input type="hidden" name="NumStudents" value="0">
<input type="button" name="AddPersonButton" value="Add Person" onclick="CloneElement('RosterTbl','NumStudents');">
</div>
</form>
<script language="javascript">
var TheForm = document.forms.EditRoster;
function CloneElement(ElToCloneId, CounterEl) {
var CloneCount = TheForm[CounterEl].value;
CloneCount++;
TheForm[CounterEl].value = CloneCount;
var ElToClone = document.getElementById(ElToCloneId);
var NewEl = ElToClone.cloneNode(true);
NewEl.id = ElToCloneId + CloneCount;
NewEl.style.display = "block";
var NewField = NewEl.children;
for (var i = 0; i < NewField.length; i++) {
var InputName = NewField[i].name;
if (InputName) {
NewField[i].name = InputName + CloneCount;
}
var insertHere = document.getElementById(ElToCloneId);
insertHere.parentNode.insertBefore(NewEl, insertHere);
}
}
</script>
Looked like you were on the right track, but I think you were taking a few extra steps, so I think I simplified it ;)
One thing you were missing was that the value of NumStudents is returned as a string so you have to call parseInt() on it.
var theForm = document.forms.EditRoster;
function insertAfter(referenceNode, newNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function CloneElement(cloneID, counterName) {
var clone = document.getElementById(cloneID);
var newClone = clone.cloneNode(true);
var counter = theForm[counterName].value = parseInt(theForm[counterName].value) + 1;
// Update the form ID
newClone.id = newClone.id + counter;
// Update the child Names
var items = newClone.getElementsByTagName("*");
for (var i = 0; i < items.length; i++) {
if (items[i].name != null)
items[i].name = items[i].name + counter;
}
insertAfter(clone, newClone);
}
Here's a working copy on jsFiddle.
P.s. I wasn't sure if you wanted the new fields clearing so I left them.

Javascript onload event function is working only on server restart

I have written a function in Javascript which will be fired on page load.
The function works fine for the first time. But if I come back to index page after visiting other pages, it does not work properly.
It does work correctly upto a certain point but skips code after that.
following is my function
<script>function populate() {
//alert("The Flag is "+$('#flag').val());
val =document.getElementById('flag').value;
xml =document.getElementById('xml').value;
alert(xml);
if (val === "M") {
if (window.ActiveXObject) {
doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = 'false';
doc.loadXML(xml);
alert("ActiveX");
} else {
var parser = new DOMParser();
doc = parser.parseFromString(xml, 'text/xml');
// alert("DOMparser");
}
alert("Value true");
/* upto here function works correctly each time
* I have also seen the values of both val and xml are coming correctly
*/
passportNo = doc
.getElementsByTagName('PASSPORT_NO')[0].childNodes[0].nodeValue;
//alert('passportNo ' + passportNo);
document.getElementById('passportNo').value = passportNo;
pass_type = doc.getElementsByTagName('PASS_TYPE')[0].childNodes[0].nodeValue;
// alert("Pass_type = " + pass_type);
if (pass_type === "I") {
document.getElementById('in').checked = true;
} else if (pass_type === "O") {
document.getElementById('out').checked = true;
}
jobNo = doc.getElementsByTagName('JOB_NO')[0].childNodes[0].nodeValue;
//alert("jobNo = "+jobNo);
document.getElementById('job_no').value = jobNo;
jobDt = doc.getElementsByTagName('JOB_DT')[0].childNodes[0].nodeValue;
//alert("jobDT "+jobDt);
document.getElementById('DT').value = jobDt;
//Clear xml
nationality =doc.getElementsByTagName('NATIONALITY')[0].childNodes[0].nodeValue;
document.getElementById('nationality2').value = nationality;
element = document.getElementById('nationality');
element.value = nationality;
}
} </script> `
and this is how I am calling it
<body onload="populate()">
<table width="1270" align="center">
<tr>
<td width="1010" height="46" colspan="3" align="center"><h1>Currency
Declaration Form</h1></td>
</tr>
</table>
<input type="hidden" id="flag" value="<%=code%>" />
<input type="hidden" id="xml" value="<%=xml%>" />
<form name="myForm" action="Entry.do" method="post"
onsubmit="return validateAll()" class = "autocompleteOff">
<table width="1042">
<tr class="heading">
</tr>
<tr>
<td width="256" align="left"><input type="radio" name="inout"
id="in" value="I" /> <label>INCOMING </label> <input type="radio"
name="inout" id="out" value="O" /> <label>OUTGOING </label></td>
<td width="774" align="right"><label>JobNo/DT</label> <input
type="text" name="job_no" id="job_no" readonly="readonly"
tabindex="-1" /> <input type="text" name="DT" id="DT"
readonly="readonly" tabindex="-1" value="<%=Convert.getSysDate()%>" /></td>
</tr>
</table>`
I can't see neither passportNo id neither PASSPORT_NO tag (getElementsByTagName) in your HTML code. Same problem with pass_type, nationality and many other elements. Do you miss some code? Or, maybe, this is dynamic output from PHP (for example) and after first run it returns different HTML?

NotFoundError: DOM Exception 8

straight to the point:
function dell(a) {
var id = a.split('');
var rs_array = ["nr", "ps", "aan", "des", "subs", "del"];
var r_array = ["artnr", "ps", "aan", "des", "subtots", "del"];
for (i = 0; i < 6; i++) //ligt aan nummer
{
var regels = document.getElementById(rs_array[i]);
regels.removeChild(document.getElementById(r_array[i] + id[3]));
}
}
With this code im trying to detele some input elements
for r = 0 to a_rows-1 step 1%>
<tr id="regels">
<td width="auto" id="nr">
<input type="text" name="artid" id="artnr<%=r%>" value="<%=records(1,r)%>" size="6">
</td>
<td id="ps">
<input type="text" name="ps" id="ps<%=r%>" onfocus="this.blur()" value="<%=records(2,r)%>" size="7">
</td>
<td id="aan">
<input type="text" name="aan" id="aan<%=r%>" onkeyup="sub(this.id,this.value);count()" value="<%=records(3,r)%>" size="2">
</td>
<td id="des">
<input type="text" name="omschr" id="des<%=r%>" value="<%=records(4,r)%>" size="50">
</td>
<td id="subs">
<input type="text" name="subtots" id="subtots<%=r%>" onfocus="this.blur()" value="<%=records(5,r)%>" size="7">
</td>
<td id="del">
<div id="del<%=r%>" onclick="dell(this.id)" style="cursor:pointer;border:1px black solid;font-size:20px">-</div>
</td>
</tr>
<% next
This comes out of the database of mine. I'm trying to delete the input elements by giving them a id with a number.
The strange thing is: I can delete the first row, but after that it says: 'NotFoundError: DOM Exception 8' when i try to delete another one.
Please help me. If you need more info about my code or something, you can ask it
It's a lot easier not to hardcode the parent element. Get the parent straight from the original element reference:
function dell(a) {
var id = a.split('');
var r_array = ["artnr", "ps", "aan", "des", "subtots", "del"];
for (var i = 0; i < r_array.length; i++) {
var element = document.getElementById(r_array[i] + id[3]);
if (element) {
element.parentNode.removeChild(element);
}
}
}

Categories