Foreach loops only through the last column of the table (ES6) - javascript

I was trying to build my first search function for a phonelist. Unfortunately it looks like, my filter function loops only trough the last column of the table.
Did i miss something? Or do i have to use a different approach for this?
PS: Pardon for the possible duplicate. All examples that i've found has been for PHP.
Many thanks in advance!
const phonelist = document.querySelector('table');
const searchInput = document.querySelector('#search');
const searchResult = document.querySelector('#search-result');
const searchValue = document.querySelector('#search-value');
// EVENTS
function initEvents() {
searchInput.addEventListener('keyup', filter);
}
function filter(e) {
let text = e.target.value.toLowerCase();
console.log(text);
// SHOW SEARCH-RESULT DIV
if (text != '') {
searchValue.textContent = text;
searchResult.classList.remove('hidden');
} else {
searchResult.classList.add('hidden');
}
document.querySelectorAll('td').forEach((row) => {
let item = row.textContent.toLowerCase();
if (item.indexOf(text) != -1) {
row.parentElement.style.display = 'table-row';
console.log(row.parentElement);
} else {
row.parentElement.style.display = 'none';
}
})
}
// ASSIGN EVENTS
initEvents();
<input id="search" />
<div class="phonelist">
<div id="search-result" class="hidden">
<p>Search results for <b id="search-value"></b>:</p>
</div>
<table class="striped">
<thead>
<tr>
<th>Phone</th>
<th>Fax</th>
<th>Room</th>
<th>Name</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>165</td>
<td>516</td>
<td>1.47</td>
<td>Johnathan Doe</td>
<td>Sales</td>
</tr>
<tr>
<td>443</td>
<td>516</td>
<td>1.47</td>
<td>Jane Dow</td>
<td>Development</td>
</tr>
</tbody>
</table>
</div>

it looks like you are querying the wrong element
document.querySelectorAll('td').forEach((row) => {
I think you want to be querying the row
document.querySelectorAll('tr').forEach((row) => {
otherwise you are of overriding your class changes with whatever is the result of the last column
(and obviously apply the class on the tr and not the parent of the tr)

Your code is actually going through all the elements but the changes from last column are overriding changes from previous columns.
Let's say you searched for dow, 2nd row 4th column is matched and shows the parent but after that your loop goes to 2nd row 5th column which doesn't match and hides the parent row.
I have updated your code, as shown below you should loop through the rows, check if any of its columns are matching and update the row only once based on the result.
const phonelist = document.querySelector('table');
const searchInput = document.querySelector('#search');
const searchResult = document.querySelector('#search-result');
const searchValue = document.querySelector('#search-value');
// EVENTS
function initEvents() {
searchInput.addEventListener('keyup', filter);
}
function filter(e) {
let text = e.target.value.toLowerCase();
console.log(text);
// SHOW SEARCH-RESULT DIV
if (text != '') {
searchValue.textContent = text;
searchResult.classList.remove('hidden');
} else {
searchResult.classList.add('hidden');
}
document.querySelectorAll('tr').forEach(row => {
let foundMatch = false;
row.querySelectorAll('td').forEach(col => {
let item = col.textContent.toLowerCase();
foundMatch = foundMatch || item.indexOf(text) > -1;
});
if (foundMatch) {
row.style.display = 'table-row';
} else {
row.style.display = 'none';
}
});
}
// ASSIGN EVENTS
initEvents();
<input id="search" />
<div class="phonelist">
<div id="search-result" class="hidden">
<p>Search results for <b id="search-value"></b>:</p>
</div>
<table class="striped">
<thead>
<tr>
<th>Phone</th>
<th>Fax</th>
<th>Room</th>
<th>Name</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>165</td>
<td>516</td>
<td>1.47</td>
<td>Johnathan Doe</td>
<td>Sales</td>
</tr>
<tr>
<td>443</td>
<td>516</td>
<td>1.47</td>
<td>Jane Dow</td>
<td>Development</td>
</tr>
</tbody>
</table>
</div>

Related

Get the all the text (single and multi-line) between HTML table tags <table><tbody><th><tr><td> and generate json

I have the below HTML Table and I want to get the data between the tags which are sometimes single line and sometimes multi-line.
<table>
<tbody>
<tr>
<th>Role</th>
<th>Device Name</th>
<th>IP Address </th>
<th>MAC Address </th>
<th>Registered </th>
<th>Subscribers </th>
<th>Events </th>
</tr>
<tr>
<td>
CM
</td>
<td>
-
</td>
<td>192.168.7.110 </td>
<td>506182488323 </td>
<td>XYZ
</td>
<td> Shkdsd30ec1
</td>
<td>Events
</td>
</tr>
</tbody>
</table>
I want to generate the JSON with this table like the below code using javascript
{
"Role" : "CM",
"Device Name" : "-",
"IP Address" : "192.168.7.110",
"MAC Address" : "506182488323",
"Registered" : "XYZ",
"Subscribers" : "Shkdsd30ec1",
"Events" : "Events"
}
If there are more tags with the key should get incremented like Role->Role1->Role2 and so on.
Assuming that you have this table alone in your HTML body...
let t = document.getElementsByTagName("table");
let trs = t[0].getElementsByTagName("tr");
let oKeys = [], oVals = [];
let ths = trs[0].getElementsByTagName("th");
let tds = trs[1].getElementsByTagName("td");
ths = Array.from(ths);
tds = Array.from(tds);
ths.map( item => {
oKeys.push(item.innerText);
return ;
});
tds.map( item => {
oVals.push(item.innerText);
return ;
});
console.log("O keys ", oKeys);
console.log("oVals ", oVals);
let newObj = {};
oKeys.map( (key, i) => {
let val = oVals[i];
Object.assign(newObj, {[key] : val })
});
console.log(newObj);
<table id="myTable">
<tbody>
<tr>
<th>Role</th>
<th>Device Name</th>
<th>IP Address </th>
<th>MAC Address </th>
<th>Registered </th>
<th>Subscribers </th>
<th>Events </th>
</tr>
<tr>
<td>
CM
</td>
<td>
-
</td>
<td>192.168.7.110 </td>
<td>506182488323 </td>
<td>XYZ
</td>
<td> Shkdsd30ec1
</td>
<td>Events
</td>
</tr>
</tbody>
</table>
newObj holds your desired data. You can add more to the above logic..
Using jQuery for dom selection, this JS code should work
var myRows = [];
var headersText = [];
var $headers = $("th");
// Loop through grabbing everything
var $rows = $("tbody tr").each(function(index) {
$cells = $(this).find("td");
myRows[index] = {};
$cells.each(function(cellIndex) {
// Set the header text
if(headersText[cellIndex] === undefined) {
headersText[cellIndex] = $($headers[cellIndex]).text();
}
// Update the row object with the header/cell combo
myRows[index][headersText[cellIndex]] = $(this).text();
});
});
// Let's put this in the object like you want and convert to JSON (Note: jQuery will also do this for you on the Ajax request)
var myObj = {
"myrows": myRows
};
console.log(myRows);
this code snippet was collected from this thread

jQuery to JavaScript (insert row after other one)

Problem: I have a small function that moves a row to the next one and back inside a table, it's in jQuery and I need it in JavaScript. Since I pretty much always work with jQuery and don't have the time to figure it out I would really appreciate it if somebody could help me do it.
I tried something like this but again I don't have the time and need it fast:
for (var i = 0; i < document.getElementsByClassName('up').length; i++) {
document.getElementsByClassName('up')[i].addEventListener('click',
function() {
let trFirst = document.getElementsByTag('tr:first');
let row = document.this.parentNode;
});
}
Solution would be this in JavaScript:
$(document).ready(function () {
$(".up,.down").click(function () {
var row = $(this).parents("tr:first");
if ($(this).is(".up")) {
row.insertBefore(row.prev());
} else {
row.insertAfter(row.next());
}
});
});
I understand that I need to learn this and can't use code I fully understand but like I said I need it quick and I know for some of you guys it's just a couple minutes work. Thanks a lot for taking the time!
function parentTr(element) {
let parent = element.parentNode;
while(parent != null) {
if(parent.nodeName === "TR") {
return parent;
}
parent = parent.parentNode;
}
}
let table = document.getElementById('table');
Array.from(document.getElementsByClassName('up')).forEach(upButton => {
upButton.addEventListener('click', function () {
let currentTr = parentTr(upButton);
let previousTr = currentTr.previousElementSibling;
if(previousTr) {
previousTr.parentNode.insertBefore(currentTr, previousTr);
}
});
});
Array.from(document.getElementsByClassName('down')).forEach(downButton => {
downButton.addEventListener('click', function () {
let currentTr = parentTr(downButton);
let nextTr = currentTr.nextElementSibling;
if(nextTr) {
currentTr.parentNode.insertBefore(nextTr, currentTr);
}
});
});
<table border="1" id="table">
<tr>
<td>row 1</td>
<td>
<button class="up">Up</button>
<button class="down">Down</button>
</td>
</tr>
<tr>
<td>row 2</td>
<td>
<button class="up">Up</button>
<button class="down">Down</button>
</td>
</tr>
<tr>
<td>row 3</td>
<td>
<button class="up">Up</button>
<button class="down">Down</button>
</td>
</tr>
</table>

ignore spaces and dashes in javascript search code

I've got a search box where as I type, table data gets filtered through and only matching results get shown. It works great; however, I want to make it better.
I want the code to ignore spaces and dashes. I'd prefer make it easy to add additional characters I want it to ignore as well in the future..
For instance...
Product Table
FH-54
TDN 256
TDN25678
FH54
In the search box, if I type FH54, I'd like both the FH-54 and the FH54 to show up. If I type in FH-54 I'd also like the FH54 and the FH-54 to show up and so on to include FH 54 as well.
If I type in TDN2 or TDN 2 in the search box, I'd like TDN 256 and TDN25678 to show up.
<b>Product Search</b><br /><form class="formatted">
<input id="Search" data-class="search_product" type="text" /></form>
<script type="text/javascript">
$('#Search').on('keyup', function(e) {
$("#noData").remove();
var value = $(this).val();
value = value.replace(/\\/g, '');
var patt = new RegExp(value, "i");
var sw = 0;
var counter = 0;
$('#Data tbody').find('tr').each(function() {
counter++;
if (!($(this).find('td').text().search(patt) >= 0)) {
$(this).not('#header').hide();
sw++;
} else if (($(this).find('td').text().search(patt) >= 0)) {
$(this).show();
}
});
if (sw == counter) {
$("#Data tbody").append(`<tr id="noData">
<td colspan="3">No data</td>
</tr>`);
} else {
$("#noData").remove();
}
});
</script>
I've tried to reconstruct your scenario the best I could and made a working example.
As per your requirement to ignore all spaces and dashes: How about removing spaces and dashes from search string and from your values within the columns?
$('#Search').on('keyup', function(e) {
$("#noData").remove();
var value = $(this).val();
var spacesAndDashes = /\s|-/g;
value = value.replace(spacesAndDashes, "");
var patt = new RegExp(value, "i");
var sw = 0;
var counter = 0;
$('#Data tbody').find('tr').each(function() {
counter++;
if (!($(this).find('td').text().replace(spacesAndDashes, "").search(patt) >= 0)) {
$(this).not('#header').hide();
sw++;
} else if (($(this).find('td').text().replace(spacesAndDashes, "").search(patt) >= 0)) {
$(this).show();
}
});
if (sw == counter) {
$("#Data tbody").append(`<tr id="noData">
<td colspan="3">No data</td>
</tr>`);
} else {
$("#noData").remove();
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<b>Product Search</b>
<br />
<form class="formatted">
<input id="Search" data-class="search_product" type="text" />
</form>
<table id="Data">
<thead>
<tr>
<th>Product Table</th>
</tr>
</thead>
<tbody>
<tr>
<td>FH-54</td>
</tr>
<tr>
<td>TDN 256</td>
</tr>
<tr>
<td>FH54</td>
</tr>
<tr>
<td>FH 54</td>
</tr>
<tr>
<td>TDN25678</td>
</tr>
</tbody>
</table>

jQuery Datatable, editing selected rows data with html text boxes

I'm fairly new to coding. I have a jQuery datatable, and when I select a row, the tds of that row fill out html textboxes above the table. I'm trying to make it so whatever is entered into those textboxes (and upon pressing the save button), is then saved into the row.
Currently I have it so it saves 1 field/td. If I press on column 0, fill out the Name textbox and press save, it saves. But it works on any column. It should only be editing the correct td. Plus I want to edit the entire row, not just one td. I'm not sure how to accomplish this. Thanks for any help!
JSFiddle
Javascript:
var table = $('#example').DataTable();
(function () {
var table = document.querySelector('#example');
var name = document.querySelector('#nameinput');
var format = document.querySelector('#formatinput');
var address = document.querySelector('#addressinput');
var report = document.querySelector('#reportinput');
var alarm = document.querySelector('#alarminput');
table.addEventListener('click', onTableClick);
function onTableClick (e) {
var tr = e.target.parentElement;
var data = [];
for (var td of tr.children) {
data.push(td.innerHTML);
}
name.value = data[0];
address.value = data[1];
format.value = data[2];
report.value = data[3];
alarm.value = data[4];
console.log(alarm.value);
}
$("#saverow").click(function() {
var table1 = $('#data-table').DataTable();
var data = [];
data[0] = name.value;
data[4] = alarm.value;
console.log(name.value);
console.log(alarm.value);
table1.draw(true);
});
})();`
I've updated my code with what I've tried so far. Currently, what I type in the textboxes, correctly is displayed in the console (upon hitting the saverow button), now I cant figure out how to save that into the table.
i think it is mor responsive to edit data right in the table.
HTML:
<table id="example" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Format</th>
<th>Report Time</th>
<th>Alarms</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>Tiger#gmail.com</td>
<td>email</td>
<td>1PM</td>
<td>Master</td>
<td class="td-button"></td>
</tr>
<tr>
<td>Bill Gates</td>
<td>111-111-1111</td>
<td>sms</td>
<td></td>
<td>Master</td>
<td class="td-button"></td>
</tr>
</tbody>
</table>
JS:
var table = $('#example').DataTable();
$("#example tbody tr").click(function(){
if (! $(this).find("button").length)
{
$(this).find("td").each(function(){
if (!$(this).hasClass("td-button"))
{
var text = $(this).text();
$(this).html ('<input type="text" value="' + text + '">')
} else
$(this).html ('<button class="button-save">Save</button>')
})
}
})
$(document).on("click", ".button-save",function(){
var tr = $(this).parent().parent();
tr.find("td").each(function(){
if (!$(this).hasClass("td-button"))
{
var text = $(this).find("input").val();
$(this).text(text)
} else
$(this).html('');
})
})
https://jsfiddle.net/91wvw619/

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>

Categories