I am trying to implement a search functionality in to an table. some thing went wrong here, put the search(filter) only considers the last column of the table.
any one help me to find out the issue please?
here is the live :
jsFiddle
my js:
var table = $('table');
$('#search').keyup(function () {
var tdText = table.find('tbody tr').find('td');
var text = $.trim($(this).val());
if(!text){
table.find('tbody tr').show();
};
tdText.filter(function() {
var reText = $(this).text();
if (reText.indexOf(text) >= 0) {
$(this).parent('tr').show();
}
else if (reText.indexOf(text) < 0) {
$(this).parent('tr').hide();
}
});
});
because when you iterating through each td, you are hiding the tr if the text is not matching so when you are iterating the last td you are hiding the row if the text is not matched
var table = $('table');
$('#search').keyup(function () {
var tdText = table.find('tbody tr').find('td');
var text = $.trim($(this).val());
if(!text){
table.find('tbody tr').show();
}else{
table.find('tbody tr').hide();
tdText.filter(function() {
var reText = $(this).text();
return reText.indexOf(text) >= 0;
}).parent().show();
}
});
Demo: Fiddle
I think you can simplify it to
var table = $('table'), $trs = table.find('tbody tr');
$('#search').keyup(function () {
var tdText = table.find('tbody tr').find('td');
var text = $.trim($(this).val());
if(!text){
$trs.show();
}else{
$trs.hide().has('td:contains('+text+')').show();
}
});
Demo: Fiddle
var tdText = table.find('tbody tr').find('td');
Will find multiple td's. This line loops through the elements and replaces tdText with the next column till last is reached.
Solution is to loop yourself
var tablecells = $('table tbody tr').find('td');
var rowText = "";
$(tablecells).each(function() {
rowText = rowText + trim($(this).val());
});
You are going through all td of all tr, but for each td you show or hide the parent row based on the search result for that td – so naturally only the result for the last td checked is what “survives” in the end for each row.
First of all, you need to split your loop, that goes over all td of all tr in one go, into two nested loops – one over the tr, and inside that one over all td of that row.
And then you should set a flag to determine whether something was found in any of the td in the row – and then at the end, you show or hide the row based on that flag.
var table = $('table');
$('#search').keyup(function () {
var text = $.trim($(this).val());
if(!text){
table.find('tbody tr').show();
}
else {
var rows = table.find('tbody tr');
rows.each(function() {
var cells = $(this).find('td'),
found = false;
cells.each(function(j, cell) {
if($(this).text().indexOf(text) >= 0) {
found = true;
}
});
if(found) {
$(this).show(); // this is here the row again
}
else {
$(this).hide();
}
});
}
});
Untested – but something along these lines should work.
Notice that I replaced .filter by .each here – your use of the former made little sense, since you where not actually doing any filtering here (that would have required that your callback function returned true or false for each element).
Related
On my js I set a click-Event for each table-row.
This works fine atm.
I try to remove the click-Event just for the last column of this table, but it doesn't work.
Do you have an idea why? Is the selector right or do I have to select more than just the last-child of td?
function addRowHandlers() {
var table = document.getElementById("klauselliste");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler =
function (row) {
return function () {
var cell = row.getElementsByTagName("td")[0];
var name = cell.innerHTML;
window.location.href = '/Klausel/Detail?Name=' + name.trim();
};
};
currentRow.onclick = createClickHandler(currentRow);
}
// Code Snippet
addRowHandlers();
$("td:last-child").unbind("click");
// Code Snippet
I recreated your code as "pure jQuery". Less code, same effort. Note the :not(:last-child), it will select all td of a row, execpt the last.
function addRowHandlers() {
$("table#klauselliste tr td:not(:last-child)").click(function() {
var name = $("td:eq(0)", $(this).parent()).html();
window.location.href = '/Klausel/Detail?Name=' + name.trim();
});
}
See here for an working example: https://jsfiddle.net/wuhtt7sc/1/
Try using .find() to locate the last element on your table.
$('#klauselliste tr').find('td:last').on('click', function (e) {
e.preventDefault();
e.stopPropagation();
});
I have this script for searching in table with Highlighting value from "input". But only for first TD in all TR.
Function remove Highlighting
function removeHighlighting(highlightedElements){
highlightedElements.each(function(){
var element = $(this);
element.replaceWith(element.html());
})
}
Function add Highlighting
function addHighlighting(element, textToHighlight){
var text = element.text();
var highlightedText = '<em>' + textToHighlight + '</em>';
var newText = text.replace(textToHighlight, highlightedText);
element.html(newText);
}
Searching in table but only in first TD in TR
$("#search").on("keyup", function() {
var value = $(this).val();
removeHighlighting($("table tr em"));
$("table tr").each(function(index) {
if (index !== 0) {
$row = $(this);
var $tdElement = $row.find('td:first');
var id = $tdElement.text();
var matchedIndex = id.indexOf(value);
if (matchedIndex != 0) {
$row.hide();
}
else {
addHighlighting($tdElement, value);
$row.show();
}
}
});
});
I don´t know how can I searching in all TD and How can I write e.g. some alert if "matchedIndex == -1" (if not found some value from input)
Try looping in all TDs of TR
$("table tr").each(function(index) {
if (index !== 0) {
row = $(this);
$("td", this).each(function(idx) {
var id = $(this).text(); //or $(this).innerText
var matchedIndex = id.indexOf(value);
if (matchedIndex != 0) {
$row.hide();
}
else {
addHighlighting($tdElement, value);
$row.show();
}
}
}
});
A short way
$("table tr > td em").each(function(){
$( this ).replaceWith( $( this ).text() );
});
Adding a span tag with a highlight class is the way to go like suggested in the comments.
Please find a working demo below and in this jsFiddle.
There is a really useful function to remove all the wrapping of the spans. You can do this with $('span.highlight').contents().unwrap().
For finding the text you can use string.search(searchText) or string.match(searchText). The search method will return -1 if nothing is found and the position of the text if found. And match would return occurences in the searchText.
For testing that it finds the first occurence I have added TestY in the table. The flag matched is responsible for this behavior. If you would remove it, it would highlight both TestY elements.
(function () {
var removeHighlight = function () {
$('span.highlight').contents().unwrap();
};
var wrapContent = function (index, $el, text) {
var $highlight = $('<span class="highlight"/>')
.text(text.substring(0, index));
//console.log(text.substring(0, index));
var normalText = document.createTextNode(text.substring(index, text.length));
//console.log(index, $highlight.text(), normalText);
$el.html($highlight).append(normalText);
};
var highlightTextInTable = function ($tableElements, searchText) {
// highlights if text found (during typing)
var matched = false;
//remove spans
removeHighlight();
$.each($tableElements, function (index, item) {
var $el = $(item);
if ($el.text().search(searchText) != -1 && !matched) {
//console.log("matched", $el, $el.html());
wrapContent(searchText.length, $el, $el.html());
//console.log(searchText, $el.text());
if (searchText == $el.text()) {
// found the entry
//console.log("matched");
matched = true;
}
}
});
};
$(function () {
//load table into object
var $tableRows = $('table tr');
var $tableElements = $tableRows.children();
//console.log($tableRows, $tableElements);
$('#search').on('keyup', function (e) {
var searchText = $(this).val();
if (searchText.length == 0) {
// catches false triggers with empty input (e.g. backspace delete or case lock switch would trigger the function)
removeHighlight(); // remove last remaining highlight
return;
}
highlightTextInTable($tableElements, searchText);
});
});
})();
.highlight {
background-color: #00FFFF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="search" />
<table>
<tr>
<td>TestX</td>
<td>Test1.2</td>
<td>Test1.3</td>
<td>Test1.4</td>
</tr>
<tr>
<td>Test2.1</td>
<td>TestY</td>
<td>Test2.3</td>
<td>Test2.4</td>
</tr>
<tr>
<td>Test3.1</td>
<td>TestY</td>
<td>Test3.3</td>
<td>Test3.4</td>
</tr>
</table>
I trying to get the <th> content of the clicked <td> item.
here is the fiddle: http://jsfiddle.net/zrccq447/
the thing is, the <th> can have colspan 2 or 3, this is the point where I am stuck. this is my code
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
var x = $('#headerx9 th:nth-child(' + (clicked_pos) + ')').text();
var xy = td.text();
alert(x);
});
i want x to be the <th> of clicked td. the problem is now that if you click on some td that shares the th with other tds, i am getting the wrong th.
appreciate any help
I've updated your JsFiddle with the answer found here: Finding a colSpan Header for one of the cells or td's is Spans
JsFiddle: http://jsfiddle.net/zrccq447/4/
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
var x = $('#headerx9 th:nth-child(' + thLocator[clicked_pos] + ')').text();
var xy = td.text();
alert(x);
});
var thLocator = [], colCount = 1;
$('#table9').find('tr:first th').each(function () {
for (var i = 0; i < this.colSpan; i++) {
thLocator.push(colCount);
}
colCount++;
});
Following on from my comment you need to sum up the colspans (or default 1) for each TH until you get enough to match the column you desire:
http://jsfiddle.net/TrueBlueAussie/zrccq447/5/
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
var cols = 0;
var $table = td.closest('table');
var $ths = $table.find('tr th');
for (var i = 1; i < $ths.length; i++) {
var $th = $ths.eq(i);
cols += ~~$th.attr('colspan') || 1;
if (cols >= clicked_pos) {
var x = $th.text();
alert(x);
break;
}
}
});
I tried to keep it generic, so it finds the appropriate table and headers on the fly.
One approach is to get store a reference to each TH, in order, in an array and call the text from the array based on the location of the td.
var thholder = $('table th'),
th = [];
for(var i = 0; i < thholder.length; i++) {
var thi = $(thholder[i]);
for(var j = 0; j < (thi.attr('colspan') || 1); j++) {
th.push(thi);
}
}
$('#table9').on('click', 'td:not(:nth-child(1))', function () {
var td = $(this);
var clicked_pos = td.index();
alert(th[clicked_pos].text());
});
http://jsfiddle.net/zrccq447/3/
This code is not optimised, but shows the approach:
Loop through all the TH in the table.
If the TH does not have the attribute 'colspan', then set the attribute to a value of 1.
Create a loop for each value of colspan and save a reference to the current TH in the array.
When you click on a TD, get it's clicked position and retrieve the text of the TH at that position in the array and alert it :)
I'm at a loss here.
I created a quick script that will add a new row to a table and also has the capability to delete a row.
jsFiddle -->http://jsfiddle.net/wLpJr/10/
What I want to achieve is this:
Display each value of each row (in the div with id='thedata')
I originally started off with adding a number at the end of each id, starting at '1', and incrementing each time the user adds a row.
//This is random code
var rowcount = parseInt($('#rowcount').val());
var newcount = rowcount + (1*1);
var x = $('#radioinput' + newcount).val('a value');
$('#rowcount').val(newcount);
The problem is that lets say you add 5 rows. Now delete row 3. When you loop through the table of data you will get an error because row "3" does not exist. You have rows 1, 2, 4, 5, 6. Specifically - the input with id = 'radioinput3' will not be present.
I then decided to do this:
$('#maintable > tbody > tr').each(function() {
radiovalue[i] = $("input[type='hidden']", this).map(function() {
var vid = 'radio' + i;
var myval = this.value;
var radioinput = document.createElement("input");
radioinput.type = "hidden";
radioinput.value = myval; // set the CSS class
radioinput.id = vid;
$('#maintable').append(radioinput);
}).get()
text1value[i] = $('td > input', this).map(function() {
var vid = 'text1pos' + i;
var myval = this.value;
var text1input = document.createElement('input');
text1input.type='hidden';
text1input.value = myval;
text1input.id = vid;
$('#maintable').append(text1input);
}).get()
text2value[i] = $('td > input', this).map(function() {
var vid = 'text2pos' + i;
var myval = this.value;
var text2input = document.createElement('input');
text2input.type='hidden';
text2input.value = myval;
text2input.id = vid;
$('#maintable').append(text2input);
}).get();
});
The problem here is that I'm getting 'undefined' values.
You are looping through a counter, which you increment everytime you add a new row, but do not take into account that a row can be deleted at any time. Instead, just use the each function to loop over the elements remaining in the DOM.
Add thead and tbody tags to your table, it will make your life easier.
I'm not sure why you have those hidden div to hold the input[type=radio] values, you don;t need them, access the values directly.
$('#showdata').click(function() {
$("#maintable tbody tr").each(function(i, v) {
var myp = "<p>Radio value is = " + $(this).find('input[type=radio]:checked').val()
+ "\nText1 value is = " + $(this).find('input[id$=text1]').val()
+ "\nText2 value is = " + $(this).find('input[id$=text2]').val() + "</p>";
$('#thedata').append(myp);
});
});
jsFiddle Demo
You could add a CSS class to the input text fields to make it easier to get, but i just used the jQuery ends with selector.
Also, you delete selector if far too high up the DOM tree on (document), instead restrict it as near as you can, in this case the #maintable.
I'm going to apply a letter-based navigation to filter the content of a table and a list. When clicking one of the letters, filters the list/table to show only the items in the list/table that start with that letter.
But the problem i'm facing is "All List". I need to display "all" link as well, Can any one please help me to add "All" link..
$(function () {
var _alphabets = $('.alphabet > a');
var _contentRows = $('#countries-table tbody tr');
_alphabets.click(function () {
var _letter = $(this), _text = $(this).text(), _count = 0;
_alphabets.removeClass("active");
_letter.addClass("active");
_contentRows.hide();
_contentRows.each(function (i) {
var _cellText = $(this).children('td').eq(0).text();
if (RegExp('^' + _text).test(_cellText)) {
_count += 1;
$(this).fadeIn(400);
}
});
});
});
Here is the Demo link...
Thanks...
Apply the Regex only when the text is not equal to All
$(function () {
var _alphabets = $('.alphabet > a');
var _contentRows = $('#countries-table tbody tr');
_alphabets.click(function () {
var _letter = $(this),
_text = $(this).text(),
_count = 0;
_alphabets.removeClass("active");
_letter.addClass("active");
_contentRows.hide();
_contentRows.each(function (i) {
var _cellText = $(this).children('td').eq(0).text();
if (_text === 'All') {
_count += 1;
$(this).fadeIn(400);
} else {
if (RegExp('^' + _text).test(_cellText)) {
_count += 1;
$(this).fadeIn(400);
}
}
});
});
});
Check Fiddle
Just show all tr onclick()
$('a').first().click(function(){
$('#countries-table tbody tr').fadeIn(400);
});
link to jsfiddle
[updated]
an easy one
Just add this line :
if(_text == 'All') _text = '.';
DEMO
Edit :
according to your wish, this code allows you to fade the letters that don't have words:
_alphabets.not(':first').css('opacity','0.5');
_contentRows.each(function(){
var beg = $(this).children('td:first').text().trim()[0];
$('.alphabet a:eq('+(beg.charCodeAt(0)-64)+')').css('opacity','1.0');
});
DEMO
Explanation: what I did here is getting the first letter of each first td in all trs then convert it to ascii (A=65 ..) then deduct 64 so that the first index starts from 1 (A) and so on (since index 0 is for "All")
Note: you don't have to use regex at all since you are just comparing the first characters, you can increase the efficiency by eleminating the regex .