I have a table that I'm manipulating through a static js file. I made a filter to show only the lines that contain the values typed in the input. For that, I add the 'hidden' class to those that don't contain the value typed in the input. However, when I go to inspect, only the first line is configured with the "hidden" class. How do I do it for all the other lines that don't contain the values typed in the input?
The code:
HTML:
<div class="container">
<hr>
<form class="form-search">
<input class="form-control" id="form-control" type="text" name="fitrar" placeholder="Buscar Registros"
autocomplete="off" autofocus />
Limpar
</form>
</hr>
<table class="table table-dark">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">CNPJ</th>
<th scope="col">CPF</th>
<th scope="col">Nome</th>
</tr>
</thead>
<tbody>
{% for registro in registros %}
<tr>
<td scope="row">{{ registro.id }}</td>
<td scope="row">{{ registro.cnpj }}</td>
<td scope="row">{{ registro.cpf }}</td>
<td scope="row">{{ registro.nome }}</td>
</tr>
JS:
const inputSearchRegistros = document.querySelector('.form-search input')
const tableRegistros = document.querySelector('.table tbody tr')
inputSearchRegistros.addEventListener('input', event => {
const inputValue = event.target.value.trim()
Array.from(tableRegistros.children)
.filter(regs => !regs.textContent.includes(inputValue))
.forEach(regs => {
regs.classList.add('hidden')
})
})
Result:
<tr>
<td scope="row" class="hidden">1</td>
<td scope="row" class="hidden">31024483000198</td>
<td scope="row" class="hidden">86520083534</td>
<td scope="row" class="hidden">Adriana teste esteves</td>
</tr>
<tr>
<td scope="row">2</td>
<td scope="row">31024483000198</td>
<td scope="row">86520083534</td>
<td scope="row">Adriana teste esteves</td>
</tr>
They are the same values, but only the first line receives the hidden class
I would like all lines that do not have the values typed in the input to receive the hidden class.
querySelector only returns the first element that matches the selector even if there is more than one match. You want to use querySelectorAll like this
const tableRegistros = document.querySelectorAll('.table tbody tr')
You'll then have to loop through the results like in ryan's answer or select the td elements and loop through those like this depending on what your trying to accomplish
const tableRegistros = document.querySelectorAll('.table tbody tr td')
inputSearchRegistros.addEventListener('input', event => {
const inputValue = event.target.value.trim()
Array.from(tableRegistros)
.filter(regs => !regs.textContent.includes(inputValue))
.forEach(regs => {
regs.classList.add('hidden')
})
})
Two problems:
You are using document.querySelector, which will only select the first row. You want to use document.querySelectorAll
You are iterating over the table cells using Array.from(tableRegistros.children).
// this only selects the first row
const tableRegistros = document.querySelector('.table tbody tr');
// this is a bunch of td elements
Array.from(tableRegistros.children)
Instead, you want to iterate over all of the rows, and then all of the cells in each row:
// use querySelectorAll to select all rows
const tableRegistros = document.querySelectorAll('.table tbody tr');
// Iterate each row
tableRegistros.forEach(row => {
// Then search all of the cells for the content
const containsText = Array.from(row.children).some(cell => cell.textContent.includes(inputValue));
if (!containsText) {
row.classList.add('hidden');
} else {
row.classList.remove('hidden');
}
});
Related
Basically where I have the 3 buttons 1, 2, and 3 in the second column first row if I type 3 the only button shows up is 3....removing buttons 1 and 2
for example if I'm looking for text with "2" in it it should still show
I want all buttons to stay regardless if they show up in the search or not...can this be achieved?
I have atleast 4 columns visible at all times and I want to search ONLY the text in the < TD > not the element text in the < TD > so radio buttons, buttons, check boxes....I want those to be immune from searches always show them as long as that particular row has the text snippet in one of the columns of that row just search the text in < TD >
Googling the right phrase has led me here because google assumes I want a checkbox to search a table....NO....I want a search to only focus on text not element text if that makes sense
Thanks
function myFunction() {
const input = document.getElementById("myInput");
const inputStr = input.value.toUpperCase();
const search_length = inputStr.length;
//alert(search_length);
document.querySelectorAll('#myTable tr:not(.header)').forEach((tr) => {
const anyMatch = [...tr.children]
.some(td => td.textContent.toUpperCase().includes(inputStr));
//fix the button issue here
if (anyMatch) tr.style.removeProperty('display');
else tr.style.display = 'none';
});
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Type to search">
<table id="myTable" border="2">
<thead><tr>
<th>Col1</th>
<th>Col2</th>
</tr></thead>
<tbody>
<tr><td>2</td><td>
<table>
<tr><td>2<button type="button">1</button></td></tr>
<tr><td>5<button type="button">2</button></td></tr>
<tr><td>9<button type="button">3</button></td></tr>
</table></td></tr>
<tr><td>test4</td><td><button type="button">5</button></td></tr>
</tbody>
</table>
If you do not want to hide the sub table rows your selector needs to only touch the outside table.
function myFunction() {
const input = document.getElementById("myInput");
const inputStr = input.value.toUpperCase();
const search_length = inputStr.length;
//alert(search_length);
document.querySelectorAll('#myTable > tbody > tr:not(.header)').forEach((tr) => {
const anyMatch = [...tr.children]
.some(td => td.textContent.toUpperCase().includes(inputStr));
//fix the button issue here
if (anyMatch) tr.style.removeProperty('display');
else tr.style.display = 'none';
});
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Type to search">
<table id="myTable" border="2">
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
</tr>
</thead>
<tbody>
<tr>
<td>2</td>
<td>
<table>
<tr>
<td>2<button type="button">1</button></td>
</tr>
<tr>
<td>5<button type="button">2</button></td>
</tr>
<tr>
<td>9<button type="button">3</button></td>
</tr>
</table>
</td>
</tr>
<tr>
<td>test4</td>
<td><button type="button">5</button></td>
</tr>
</tbody>
</table>
I have a html table with multiple rows and columns. I want to pull all the values by column id and compare with some matching string. If matches i want to enable a button on the page.
Could you please let me know how to refer the column by id in $(document).ready function.
Here is the table
<table id="data" class="table">
<thead>
<tr class="DataT1">
<th>Id</th>
<th>Name</th>
<th>Place</th>
</tr>
</thead>
<th:block th:each="it : ${data}">
<tr>
<td th:text="${it.id}">id</td>
<td th:text="${it.name}">name</td>
<td th:text="${it.place}">place</td>
</tr>
</th:block>
</table>
Button:
style="visibility:hidden">Submit
$(document).ready(function(){
//here i want to pull the place column and verify if one of the
places matches my input string enable submit button
$("#submitbutton").css("visibility", "visible");
}
}
This function will take all information inside you td and search for the string you looking for :
But i cannot get the point that you search for a particular string instead of searching for an object.
const addresses = [...document.querySelectorAll(".address")];
const serchFromList = (arr, str) => {
return arr.map(el =>
el = el.innerHTML
).filter(el => el === str)
}
console.log(serchFromList(addresses, "NY"))
/* in case you want a boolean you can use some*/
const isAddressExist = (arr, str) => {
return arr.map(el =>
el = el.innerHTML
).some(el => el === str)
}
console.log(isAddressExist(addresses, "NY"))
<table id="data" class="table">
<thead>
<tr class="DataT1">
<th>Id</th>
<th>Name</th>
<th>Place</th>
</tr>
</thead>
<th>
<tr>
<td>4545</td>
<td>5454</td>
<td>65687</td>
</tr>
<tr>
<td>aziz</td>
<td>david</td>
<td>paul</td>
</tr>
<tr>
<td class='address'>NY</td>
<td class='address'>MTL</td>
<td class='address'>BC</td>
</tr>
</th>
</table>
Should be pretty doable with XPath if you don't want to add extra attributes to Place cell. Just find out the position of Place column and get the text from the same position of <td>.
// Get the table node first
let node = document.getElementById('data')
// Find out position of `Place` column
let nth = document.evaluate('count(//th[text()="Place"]/preceding-sibling::*)+1', node).numberValue
// Get all the place cell by the position
let placeCells = document.evaluate(`//td[position()=${nth}]`, node)
// Get all the place names
let places = [],
placeNode = placeCells.iterateNext()
while (placeNode) {
places.push(placeNode.textContent)
placeNode = placeCells.iterateNext()
}
console.log(places)
// ['NYC', 'SF', 'LA']
<table id="data" class="table">
<thead>
<tr class="DataT1">
<th>Id</th>
<th>Name</th>
<th>Place</th>
</tr>
</thead>
<tbody>
<tr>
<td>0001</td>
<td>Mary</td>
<td>NYC</td>
</tr>
<tr>
<td>0002</td>
<td>John</td>
<td>SF</td>
</tr>
<tr>
<td>0003</td>
<td>Bob</td>
<td>LA</td>
</tr>
</tbody>
</table>
I'm using html5 and jquery to set up a dynamic table, until then I can add the elements to the table without problems, but I can not retrieve the value of its columns. so I have the following questions:
How can I recover the table data by clicking the ROW?
Should I always use the data-name, id for example as in the first
line ?
$(document).on("change", "#TabClientesAdicionados", function(e) {
alert('?');
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<hr>
<table id="TabClientesAdicionados" class="table table-hover">
<thead>
<tr>
<th> ID </th>
<th> Name </th>
<th> Actions </th>
</tr>
</thead>
<tbody>
<tr>
<td data-id="Bruno">1</td>
<td data-nome="Bruno">Bruno</td>
<td>Details</td>
</tr>
<tr>
<td>2</td>
<td>Josep</td>
<td> Details </td>
</tr>
</tbody>
</table>
How can I recover the table data by clicking the ROW?
You can bind the click event to your TR elements and get the information.
Should I always use the data-name, id for example as in the first line?
Yes, because you don't want the parsed HTML to manipulate data. The data attributes are a better approach to keep related data (no HTML) to DOM elements.
Look at this code snippet
This approach binds the click event to TR elements
$('#TabClientesAdicionados tbody tr').click(function() {
var data = { name: '', id: '' };
$(this).children('td').each(function() {
var name = $(this).data('nome');
if (name) {
data.name = name;
}
var id = $(this).data('id');
if (id) {
data.id = id;
}
});
console.log(data);
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<hr>
<table id="TabClientesAdicionados" class="table table-hover">
<thead>
<tr>
<th> ID </th>
<th> Name </th>
<th> Actions </th>
</tr>
</thead>
<tbody>
<tr>
<td data-id="Bruno_1">1</td>
<td data-nome="Bruno">Bruno</td>
<td>Details</td>
</tr>
<tr>
<td>2</td>
<td>Josep</td>
<td> Details </td>
</tr>
</tbody>
</table>
I would do as the following snippet.
You need to bind the event to the row tr ant then get each of its children.
By adding a data attribute you could set a column name. This could also help if you eventually needed to extract the value of an specific cell.
Incidentally you could also add a second data attribute named like data-value or something similar- This in case you are worried that your parsed html content might cause you trouble with the values.
$(document).ready(function() {
$("#mytable").on('click', 'tr', onCellClick);
//Bind the event to the table row
function onCellClick() {
let row = $(this); //get the jquery Object for the row
let rowValues = {}; //An empty object to hold your data
let temp;
//extract the value of every cell in the row
//Doing it this way gives you flexibility on the amount of colums you have
row.find('td').each(function(item) {
temp = $(this);
rowValues[temp.data('column')] = temp.text();
//this could be changed to
//rowValues[temp.data('column')] = temp.data('value);
//if you desire to use a separate data-value property
});
console.log(rowValues);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table style="width:100%" id="mytable">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td data-column="name" data-value="Jill">Jill</td> <!-Adding value property-->
<td data-column="lastname">Smith</td>
<td data-column="age">50</td>
</tr>
<tr>
<td data-column="name">Eve</td>
<td data-column="lastname">Jackson</td>
<td data-column="age">94</td>
</tr>
</table>
I have this table in html, and I load it with Php Laravel
<div class="form-row col-md-12">
<table id="contacts" class="table table-striped">
<tbody>
<tr>
<th>Id</th>
<th>Cel</th>
<th>Tel</th>
<th>Email</th>
<th>Actions</th>
</tr>
#if(isset($contacts) && count($contacts)>0)
#foreach($contacts $c)
<tr>
<td class="inf" data-id="{{ $c->id }}"> {{ $c->id }} </td>
<td class="inf" data-cel="{{ $c->cel}}"> {{ $c->cel}} </td>
<td class="inf" data-tel="{{ $c->tel}}"> {{ $c->tel}}</td>
<td class="inf" data-email="{{ $c->email }}"> {{ $c->email }} </td>
<td>
<button class='btn btn-primary btnAlterarContato' type="button">Alterar</button>
</td>
</tr>
#endforeach
#endif
</tbody>
</table>
</div>
You can see that each row has its data attribute for creating data. I made a method that I can retrieve the data from the TD and alter them, however I can not change the data of the data. how do I change how information that is without data attribute?
$('.btnAlterarContato').click(function(){
var Row= $(this).closest('tr');
var Posicao = 1;
// Switch: 1 = Id, 2 = Cel, 3 = Tel, 4 = Email
Row.find('td').each(function(){
switch(Posicao)
{
case 2: $(this).text('new value '); $(this).attr('data-cel', 'Hi');
$(this).data('data-cel','Hi') ;break;
}
Posicao++;
});
});
I have a repeat loop to walk on every table td, and in case position 2 is the value of cel, I would like to change your display item and your cell-date when I do $ (this) .text ('new value ') this works, but I can not change the mobile date, how do I do this?
For changing data attribute use .data() like below:-
$(this).data('cel', 'Hi');
Note:- Once clear your browser cache and check
I create the table like so:
<table class="table" id="tbl_items">
<thead>
<tr>
<th>
Id
</th>
<th>
Item
</th>
<th>
Serial Key
</th>
<th>
Brand
</th>
<th>
Quantity
</th>
<th>
Description
</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
ViewBag.AccountID = item.AccountId.ToString();
if (item.Items != null)
{
foreach (var itemOnList in item.Items)
{
<tr>
<td class="cls-itemid" data-itemid="#itemOnList.ItemId">#Html.DisplayFor(model => itemOnList.ItemId)</td>
<td class="cls-itemname" data-itemname="#itemOnList.ItemName">#Html.EditorFor(model => itemOnList.ItemName)</td>
<td class="cls-serialnumber" data-serialnumber="#itemOnList.SerialNumber">#Html.EditorFor(model => itemOnList.SerialNumber)</td>
<td class="cls-brandname" data-brandname="#itemOnList.BrandName">#Html.EditorFor(model => itemOnList.BrandName)</td>
<td class="cls-quantity" data-quantity="#itemOnList.Quantity">#Html.EditorFor(model => itemOnList.Quantity)</td>
<td class="cls-description" data-description="#itemOnList.Description">#Html.EditorFor(model => itemOnList.Description)</td>
<td>
Edit |
Delete
</td>
</tr>
}
}
}
</tbody>
I am trying to get the value of td in a row using this:
$(".btn_edit").click(function() {
var row = $(this).closest("tr");
var text = row.find(".cls-itemname").text();
alert(text);
});
The alert box has no value. I cannot use the data-item because when I change the value of the #Html.EditorFor boxes, it gives the old values and not the new ones.
Since you use #Html.DisplayFor() which returns an <input> element... I guess you want to have the input's text...
This will work:
$(".btn_edit").click(function() {
var row = $(this).closest("tr");
var text = row.find(".cls-itemname input").val(); // <-- Look the change here
alert(text);
});
There is simply no text in the .cls-itemname element... But there's an input having a value. Use .val() against the input.