Restrict 1st table row for datatables - javascript

Hi I am currently working on datatables and I wrote a code when a table row has been click there is a specific function that will be called.
The problem is when I click the table row for the table header it also does the function (IT MUST NOT).
Here is a snippet of my code when I click the table row there will be a function called.
$('#response-contact-container').on('click', 'tr', function(){
var table = $('#response-contact-container').DataTable();
var data = table.row(this).data();
$('#edit-contact-settings').modal('hide');
$('.modal-backdrop').remove();
var community_contacts = ['c_id','firstname','lastname','prefix','office','sitename','number','rel'];
var employee_contacts = ['eid','firstname','lastname','nickname','birthday','email','numbers','grouptags'];
var counter = 1;
var container = document.getElementById("contact-settings-wrapper");
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
for(var i=1; i< data.length; i++) {
var label = document.createElement("label");
var input = document.createElement("input");
if (data[0].charAt(0)=="c") {
var t = document.createTextNode(community_contacts[i].capitalize());
label.appendChild(t);
container.appendChild(label);
input.type = "text";
input.name = community_contacts[i];
input.className = "form-control";
input.value = data[i];
container.appendChild(input);
container.appendChild(document.createElement("br"));
} else {
var t = document.createTextNode(employee_contacts[i].capitalize());
label.appendChild(t);
container.appendChild(label);
input.type = "text";
input.name = community_contacts[i];
input.className = "form-control";
input.value = data[i];
container.appendChild(input);
container.appendChild(document.createElement("br"));
}
console.log(data[i]);
counter++;
}
$('#edit-contact').modal('show');
});
I want the header be able to not perform the function under the onclick in jQuery, but I don't want it to disable because I want to use the datatables built in feature that sort the cells.
Thanks

I interpret your question to be the following: when I click on a table row, can I call a click handler if and only if that row has <td> elements, not <th> elements, i.e. only when it is a non-header row?
To accomplish this, use the jQuery .has() selector. Specifically, in your code, instead of
...on('click', 'tr', ...
use
...on('click', 'tr:has(td)', ...
In the example below, the selected element's currentTarget result shows that it is indeed the row, and not the cell, that is the click's current target. Moreover, it calls the handler function (or not) as follows:
when you click on a normal data row, i.e. a row with all <td> cells
not when you click on a normal header row, i.e. a row with all <th> cells
when you click on a mal-formed row that (inappropriately) contains both <th> and <td> rows
You should never form a table row in the last way. However, that example show how the selector is working. Specifically, even if you click on the <th> cell in that row, the click handler will still fire because you are clicking on a cell in a row that contains at least one <td> cell. That should never be what you want, but it illustrates what's going on in terms of what is actually being selected.
var counter = 0;
$('#myTable').on('click', 'tr:has(td)', function(e) {
console.log(e.currentTarget);
});
$('#myTable').on('click', 'tr', function(e) {
counter += 1;
console.log(counter + ' clicks');
});
table {
border-collapse: collapse;
}
td, th {
border: black solid 1px;
padding: 0.5em;
text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<th>normal header row - cell #1 - <th></th>
<th>normal header row - cell #2 - <th></th>
</tr>
<tr>
<th>malformed (mixed) row - cell #1 - <th></th>
<td>malformed (mixed) row - cell #2 - <td></td>
</tr>
<tr>
<td>normal data row - cell #1 - <td></td>
<td>normal data row - cell #2 - <td></td>
</tr>
</table>

Related

Search through HTML table columns

I am developing a site that contains a live search. This live search is used to search for contacts in a contact list (An HTML table). The contact list is a table with 2 columns, with each column containing a contact. The search works but, it returns the whole row, not just the matching columns.
Meaning that if I search for A in a table like the one in the snippet below; the search returns the whole row ( A || B ), not just A. Is there any way I could refine my function to search through columns instead of rows?
Hope I explained myself clearly.
<table>
<tr>
<td>A</td>
<td>B</td>
</tr>
<tr>
<td>C</td>
<td>D</td>
</tr>
</table>
Function
<script>
function myFunction() {
//variables
var input, filter, table, tr, td, i;
input = document.getElementById("search");
filter = input.value.toUpperCase();
table = document.getElementById("table");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td)
{
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
</script>
I've modified your code to iterate all the td elements in your table. instead of hiding the cells that don't contain the filter text I've opted to apply an opacity to them. It makes it clearer in the example what is happening.
When doing work on key down, don't forget to debounce the event. See this post for a good introduction: https://davidwalsh.name/javascript-debounce-function
function myFunction() {
//variables
var
input = document.getElementById("search"),
filter = input.value.toUpperCase(),
table = document.querySelector('table'),
cells = table.querySelectorAll('td');
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
if (cell.innerHTML.toUpperCase().indexOf(filter) > -1) {
cell.classList.remove('no-match');
} else {
cell.classList.add('no-match');
}
}
}
const
form = document.getElementById('form'),
input = document.getElementById("search");
form.addEventListener('submit', onFormSubmit);
input.addEventListener('keyup', onKeyUp);
function onFormSubmit(event) {
event.preventDefault();
myFunction();
}
function onKeyUp(event) {
// Debounce this event in your code or you will run into performance issues.
myFunction();
}
.no-match {
opacity: .2;
}
<form id="form">
<label>
Filter text
<input type="text" id="search"/>
</label>
<button>Filter</button>
</form>
<table>
<tr>
<td>A</td>
<td>B</td>
</tr>
<tr>
<td>C</td>
<td>D</td>
</tr>
</table>

How to get the row wise and column wise table data of a selected cell in js

[![This is a table designed using HTML][1]][1]
Hi,
In this table any cell can be selected by the user(even multiple cells).What i need is that once the submit button is pressed the corresponding row wise and column wise table data i.e B and 1pm as of this example must be stored in the database.
<script type="text/javascript">
function change()
{
var cells = document.querySelectorAll("td");
for (var i = 0; i < cells.length; i++) {
cells[i].addEventListener("click", function() {
this.className= this.className == "white" ? "green" : "white";
});
}
}
function alert()
{
var cells = document.querySelectorAll("td");
for(var i=0;i<cells.length;i++)
{
if(cells[i].className.match("green"))
{
document.getElementById('p1').innerHTML="Appointment fixed";
}
}
}
</script>
This is the js for cell selection and alert message on submit if any one of the cells is selected
I'm new to js,so someone kindly help me out with this.Thankyou.
In the HTML of each td element you can save its column name and row name like this
<td data-r="Fairlands_B" data-c="1pm" class="green"></td>
Then to get the row and column data out of the clicked td:
var place=this.dataset.r;
var time=this.dataset.c;

How to get value of text box embeded in cell

I have the following code
<tr val='question'>
<td>
<input style='width: 500px' type='text' placeholder='Q.Enter your question here for radio button? '>
</tr>
How can i find the value of input box embedded in cell .
function saveUserDefQues(){
var table=document.getElementById("QuestionList");
var surveyquestionform=document.forms[0];
var count=$('#QuestionList tr').length
for (var i = 0; i<count; i++) {
var row = table.rows[i];
if(row.getAttribute('val')==='question')
{
var Cells = row.getElementsByTagName("td");;
}
}
}
document.querySelector('tr[val] > td > input').value;
Array.from(document.querySelectorAll('tr[val] > td > input')).forEach(function(entry, index, entries)
{
entry.value; // you may store the value OR process with it AS you see fit
});
Since you are using Jquery this can be done this way.
replace this line of code
var Cells = row.getElementsByTagName("td");
with
var Cells = $(row).find('td');
var inputValue = Cell.find('input').val(); // gives you value of input
Code Refactoring recommended
I would like to refactor your code as below
HTML
<tr data-val='question'> // use data-* attribute to add custom attributes into tags
<td>
<input style='width: 500px' type='text' placeholder='Q.Enter your question here for radio button? '>
</td> // close your td
</tr>
Script
function saveUserDefQues(){
var surveyquestionform = document.forms[0]; // not sure what this is for, so ill leave it as is.
$('#QuestionList tr[data-val="question"]').each(function(){ //loop all tr's which has the data-val set to question
var inputValue = $(this).find('td input').val(); //get the value of input
console.log(inputValue);
});
}
$("tr[val='question'] > td > input").val()
But first you need to write a valid HTML. </td> closing tag is missing. Also you need to put this tr in a <table>.
See this Plunker
function getResult(){
$( "tr" ).each(function( index ) {
console.log($(this).find('input').attr('placeholder') );
});
}

delete row in table with javascript

Apologies if something similar has been posted but I am trying to delete a row the button is on and not just the last row as the search results seem to give me.
I have the following code that adds to an HTML table but onclick doesn't work, the delete button doesn't work and addRow doesn't function. Why not?
java code
function addRow() {
var table = document.getElementById("createOrderTable");
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
... other cells ...
var cell4 = row.insertCell(3);
var btn = document.createElement("input");
btn.type = "button";
btn.value = "Close";
btn.onclick = deleteRow('createOrderTable', rowCount);
cell4.appendChild(btn);
}
function deleteRow(id, row) {
document.getElementById(id).deleteRow(row);
}
table code
<table id="createOrderTable" width="100%">
<tr>
<th>Count</th><th>Product</th><th>Mesh</th><th>Delete</th>
</tr>
<tr>
<td>1</td><td>OL</td><td>200</td><td><button type="button" class="close" aria-hidden="true" onclick="deleteRow('createOrderTable', 1)">×</button></td>
</tr>
</table>
if I change
btn.onclick = deleteRow('createOrderTable', rowCount );
to
btn.onclick = deleteRow('createOrderTable', rowCount + 1 );
I can get the row to show but it throws
Uncaught IndexSizeError: Failed to execute 'deleteRow' on 'HTMLTableElement': The index provided (3) is greater than the number of rows in the table (3).
and doesn't show the button. I'm confused about what I'm doing wrong here.
The row index is not static, so as you delete rows, the row index of remaining rows can change if a row with a lower index is deleted. A solution is to not use rowIndex at all, and just use DOM relationships instead.
You can get a reference to the button that was clicked by passing this to the function, then go up parent nodes until you reach a TR element and delete it, e.g.
// Helper function:
function upTo(el, tagName) {
tagName = tagName.toLowerCase();
while (el && el.parentNode) {
el = el.parentNode;
if (el.tagName && el.tagName.toLowerCase() == tagName) {
return el;
}
}
return null;
}
function deleteRow(el) {
var row = upTo(el, 'tr')
if (row) row.parentNode.removeChild(row);
}
<table>
<tr>
<td>1</td><td>OL</td><td>200</td>
<td><button type="button" onclick="deleteRow(this)">×</button></td>
</tr>
<tr>
<td>2</td><td>AB</td><td>400</td>
<td><button type="button" onclick="deleteRow(this)">×</button></td>
</tr>
</table>
You can also use event delegation and put a single listener on the table, then use the associated event object's target property to see if the event was initiated by a click on a button with class close. If so, call deleteRow and pass the element reference as a parameter as for the above.
You shoud modify your code like this:
btn.onclick = deleteRow;
And the deleteRow declaration to this:
function deleteRow() {
this.parentElement.parentElement.remove();
}
UPDATE
Check working example.
To delete the current row that the button belongs to
Change onclick of <button> to :
onclick="this.parentNode.parentNode.parentNode.deleteRow(this.parentNode.parentNode.rowIndex)"
or change button in html like:
<input type="button" onclick="deleteRow(this)">X</button>
or by JavaScript code using
btn.setAttribute('onclick','deleteRow(this)');
Delete function is like:
function deleteRow(el) {
var tbl = el.parentNode.parentNode.parentNode;
var row = el.parentNode.parentNode.rowIndex;
tbl.deleteRow(row);
}

Add/Remove rows dynamically in a table in javascript

I want to add/remove rows in a table dynamically. I have javascript function to add and remove the rows. But, I want the delete button beside every single row so that I can delete a particular row.
ANd I want to add a row only if the first row is completely filled.
function to remove row
function removeRowFromTable()
{
var tbl = document.getElementById('tblSample');
var lastRow = tbl.rows.length;
if (lastRow > 2) tbl.deleteRow(lastRow - 1);
}
function to add rows:
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "text";
cell1.appendChild(element1);
var cell2 = row.insertCell(1);
var element2 = document.createElement("input");
element2.type = "text";
cell2.appendChild(element2);
}
my table:
<table id="tableId">
<tr><td>Host Name</td><td>Directory</td></tr>
<tr><td><input type="text"/></td><td><input type="text"/></td></tr>
<tr><td><input type="button" value="+" onclick="addRow(tableId)"/></td>
<td><input type="button" value="-" onclick="removeRowFromTable()"/></td></tr>
</table>
Any help is appreciated! Thanks in Advance!!!
If you put a delete button on each row, then:
<tr>
<td><input type="button" value="Delete row" onclick="deleteRow(this)">
<td><input type="text">
<td><input type="text">
</tr>
And the deleteRow function can be:
function deleteRow(el) {
// while there are parents, keep going until reach TR
while (el.parentNode && el.tagName.toLowerCase() != 'tr') {
el = el.parentNode;
}
// If el has a parentNode it must be a TR, so delete it
// Don't delte if only 3 rows left in table
if (el.parentNode && el.parentNode.rows.length > 3) {
el.parentNode.removeChild(el);
}
}
BTW, if all your rows have the same content, it will be much faster to add a row by cloning an existing row:
function addRow(tableID) {
var table = document.getElementById(tableID);
if (!table) return;
var newRow = table.rows[1].cloneNode(true);
// Now get the inputs and modify their names
var inputs = newRow.getElementsByTagName('input');
for (var i=0, iLen=inputs.length; i<iLen; i++) {
// Update inputs[i]
}
// Add the new row to the tBody (required for IE)
var tBody = table.tBodies[0];
tBody.insertBefore(newRow, tBody.lastChild);
}
You can avoid a lot of cross browser headaches by using jquery. Here is a sample.
http://jsfiddle.net/piyushjain7/gKJEs/
Javascript has this really useful function called deleteRow where if you know the index you are deleting from, you can simply input that number, and then it'll delete that specific row (index's starting at 0 - tbl.rows.length).
I also found a nice example that uses it in action. You can adjust it to fit your needs though (although his uses checkboxes which might be a lot cleaner than just making a button next to every single row). I don't encourage you to blatantly copy the code so if there is anything that confuses you, please let us know. Hope this helps.
EDIT: I didn't see you wanted to add rows after you found out the last row was completely filled. I'll update my answer when I figure that out. However, the basic idea of that is to check if the <td> tag has text in it (perhaps check if the text inside the tag isn't a blank or if there is a <td> tag at all and then if it isn't empty, make a new <tr> element else don't.
See http://jsfiddle.net/9gnAx/
HTML & JavaScript (body):
<table id="tableId">
<tr>
<th>Host Name</th>
<th>Directory</th>
<td><input class="add" type="button" value="+" /></td>
</tr>
<tr>
<td></td><td></td>
<td><input class="add" type="button" value="+" /></td>
</tr>
</table>
<script type="text/javascript">
(function(){
var els=getElementsByClassName("add","tableId");
for(var i=0;i<els.length;i++){
els[i].onclick=addRow;
}
els[0].onclick();
})();
</script>
CSS (head):
.add,.del{
width:25px;
}
JavaScript (head):
function getElementsByClassName(c,el){
if(typeof el=='string'){el=document.getElementById(el);}
if(!el){el=document;}
if(el.getElementsByClassName){return el.getElementsByClassName(c);}
var arr=[],
allEls=el.getElementsByTagName('*');
for(var i=0;i<allEls.length;i++){
if(allEls[i].className.split(' ').indexOf(c)>-1){arr.push(allEls[i])}
}
return arr;
}
function killMe(el){
return el.parentNode.removeChild(el);
}
function getParentByTagName(el,tag){
tag=tag.toLowerCase();
while(el.nodeName.toLowerCase()!=tag){
el=el.parentNode;
}
return el;
}
function delRow(){
killMe(getParentByTagName(this,'tr'));
}
function addRow() {
var table = getParentByTagName(this,'table')
var lastInputs=table.rows.length>2?
table.rows[table.rows.length-2].getElementsByTagName('input'):[];
for(var i=0;i<lastInputs.length-1;i++){
if(lastInputs[i].value==''){return false;}
}
var rowCount = table.rows.length;
var row = table.insertRow(rowCount-1);
var cell1 = row.insertCell(0);
var element1 = document.createElement("input");
element1.type = "text";
cell1.appendChild(element1);
var cell2 = row.insertCell(1);
var element2 = document.createElement("input");
element2.type = "text";
cell2.appendChild(element2);
var cell3 = row.insertCell(2);
var element3 = document.createElement("input");
element3.type = "button";
element3.className="del";
element3.value='-';
element3.onclick=delRow;
cell3.appendChild(element3);
}
Update:
RobG has made me realize that getParentByTagName throws an error if there isn't any parent with the nodeName passed.
If you want a more general getParentByTagName, which doesn't throw errors, you can use
function getParentByTagName(el,tag){
tag=tag.toLowerCase();
while(el&&el.nodeName.toLowerCase()!=tag){
el=el.parentNode;
}
return el||null;
}
And when you call the function you should check if the result is null.
Updated jsfiddle: http://jsfiddle.net/9gnAx/1/

Categories