multi column search in a table using jquery (Algorithm needed)? - javascript

I need to write a multi column search in a table. Due to some reason (support issue), I am unable to use datatable and table sorter plugin. I need your help in algorithmic part that how can I make multi column search. Please do not give me the link of already created plugins since I have changed table structure too much and I am unable to use those. I need something like this
datatables.net/examples/api/multi_filter.html
if I will get the hint for how its algo works, I will write the same function for me. I have written this code, but it is working on single column search, when I am searching in another column, it resets the search in multi column.
function searchonKeyPress(input_text_box)
{
var query = $.trim(input_text_box.val());
query = query.replace(/ /gi, '|');
if(query=='undefined')
return false;
var index_input = input_text_box.closest("th").index();
index = $("#freeze-tableFreeze .GridviewScrollItem tr:eq("+index_input+") td").length;
$("#freeze-tableFreeze .GridviewScrollItem").each(function() {
var tr_ident = $(this).attr('tr_ident');
var column_text = $(".GridviewScrollItem[tr_ident='"+tr_ident+"'] td:eq("+index_input+")").text();
(column_text.search(new RegExp(query, "i")) < 0) ? $(this).hide().removeClass('visible') : $(this).show().addClass('visible');
});
pagignation(1);
}
I need something like this:

Try this if you want to search in all the table: DEMO
If you want to search by column try this :DEMO
HTML:
<table>
<thead>
<tr>
<th>One<input type='text' class='search' /></th>
<th>Two<input type='text' class='search' /></th>
<th>Three<input type='text' class='search' /></th>
<th>Four<input type='text' class='search' /></th>
</tr>
</thead>
.........
JQuery:
$('.search').blur(function(){
$("td").removeClass('selected','');
var index=$(this).index('.search')+1;
$('.search').each(function(index , val){
var tag=$(val).val();
if(tag!='') $("tr td:contains("+tag+")").addClass('selected');
});
});

The simplest solution here would be to select all td's in your table and filter them using jQuery :contains() selector with the search phrase and highlight the rows / columns.
Take a look into this simple example. This selects all the cells with keyword 'one'.
$('td:contains(one)').css('color', 'red');
Update :
New sample with search box code.

For filtering you can use JQuery and manually iterate through the html markup to show/hide certain rows dependent on the filter criteria...
I build a small example of how to achieve this. Because you didn't provide any code, you'll have to adopt it
http://jsfiddle.net/Elak/FxBhQ/
The JQuery part is not overly complex, of cause you have to extend it to what ever functionality you want to have...
$(document).ready(function () {
$(".searchBox").change(function () {
var search = $(this).val();
$(".column").each(function () {
if ($(this).text().indexOf(search)) {
$(this).parent().hide();
}
});
});
});

Related

Filter Table with JQuery using the “each” element

OK everybody, I hope you can help me. I have a problem with JQuery or better with the each selector of JQuery.
I have an example table, where I want to filter for special values which I entered before. Those values I got from my input field , store them in a variable, split the data an create an JQuery Object.
Well and then I think I have a problem with the selection, marked in the code section.
<p>
<input id="testyear" size="4" type="text">
<input value="Werte" onclick="getvalue()" type="button">
</p>
<script>
function getvalue() {
var wert = $('#testyear').val();
$("#years").find("tr").hide();
var data = this.value.split(" ");
// create jQuery Object
var jQueryObject = $("#years").find("tr");
// i think here is my error, i want to display only the object which are equal or better stored in my variable “wert”.
$.each(data, function (){
//jQueryObject = jQueryObject.filter(wert);
jQueryObject == wert;
});
jQueryObject.show();
};
<!--Example Table-->
<table id="years">
<tbody>
<tr>
<td>1997</td>
<td class="century">20</td>
</tr>
<tr>
<td>2001</td>
<td class="century">21</td>
</tr>
</tbody>
</table>
I expect, that when I enter 1997 in the inpt field, the whole tr which contains 1997 will be displayed. I know it is simple but I have no idea so thanks for your help.
Use a filter on the TR's after initially hiding them all.
e.g.
getvalue = function() {
var wert = $('#testyear').val();
// create jQuery Object
$("#years tr").hide().filter(function() {
return ~~$("td", this).first().text() >= wert;
}).show();
};
JSFiddle: https://jsfiddle.net/TrueBlueAussie/h8Lejfac/
Notes:
The ~~ is a little conversion to integer trick
You seem to have extra code you do not need in the example
Just get filter to return true for each item you want to keep and false for the rest
When using jQuery, avoid using inline event handlers (like onclick=). Use jQuery event handlers instead. See below:
e.g.
$('#wert').click(function() {
var wert = $('#testyear').val();
// create jQuery Object
$("#years tr").hide().filter(function() {
return ~~$("td", this).first().text() >= wert;
}).show();
});
JSFiddle: https://jsfiddle.net/TrueBlueAussie/h8Lejfac/1/
I think your problem is not in each() method (not selector). Your problem is here:
var data = this.value.split(" ");
this is not defined (you are not in an object scope). I think you need this:
var data = wert.split(" ");
-----------^^^^
You've obtain the value of wert in the last line.

How to automatically call a JavaScript that modify a value before show this value?

I am very new in JavaScript and I have the following problem to solve.
I have a table that contains this td cell:
<td class= "dateToConvert" width = "8.33%">
<%=salDettaglio.getDataCreazione() != null ? salDettaglio.getDataCreazione() : "" %>
</td>
This retrieve a String from an object and show it into the cell
The problem is the retrieved string represent a date having the following horrible form: 20131204 and I have to convert it into the following form: 2013-12-04.
So I am thinking to create a JavaScript that do this work when the value is retrieved.
My problem is: how can I do to automatically call the JavaScript before to show the value into the td cell? (So I show the modified output in the desidered form)
EDIT 1:
So I have create thid JavaScript function into my page:
function convertData() {
var tds = document.querySelectorAll('.dateToConvert');
[].slice.call(tds).forEach(function(td) {
td.innerText = td.innerText.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
});
}
But it don't work because it never enter in this function (I see it using FireBug JavaScript debugger). Why? What am I missing? Maybe have I to call it explicitly in some way in my td cell?
Of course it is better to fix backend method to make it return proper format. But since you have no control over it try to use something like this:
var tds = document.querySelectorAll('.dateToConvert');
[].slice.call(tds).forEach(function(td) {
td.textContent = td.textContent.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
});
Check the demo below.
var tds = document.querySelectorAll('.dateToConvert');
[].slice.call(tds).forEach(function(td) {
td.textContent = td.textContent.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
});
<table>
<tr>
<td class= "dateToConvert" width = "8.33%">
20131204
</td>
<td class= "dateToConvert" width = "8.33%">
20140408
</td>
</tr>
</table>

How do I reference a table row using jQuery

Afternoon,
I wish to pass the row number of a table to a function to reference that specific row in that specific table, for example say I have this:
<table id="foo">
<tr><td>some stuff...</td><tr>
<tr><td>stuff</td><tr>
<tr><td>more stuff</td><tr>
<tr><td>some stuff</td><tr>
<tr><td>some stuff</td><tr>
</table>
and I have looped through the table rows and obtained the index, so in this example say I wanted to do something with the third row (which would have an index of 2, the one which has the contents "more stuff"). And I passed this through a function, like this
manipulateRow(2)
and this is my whole function
function manipulateRow(rowIndex){
/* do something */
}
How do you refer the rowIndex parameter to the table within the function? For example:
$('#foo').child("tr")[rowIndex].html('<td>i now contain even more stuff!</td>'); // I know this is wrong, how do I make it right?
Sorry if I'm being a bit thick or not explaining myself.
Easy.
$("#foo tr:eq("+rowIndex+")").html("<td>i now contain even more stuff!</td>");
Learn more about jQuery selectors here: http://api.jquery.com/category/selectors/
that could work actually only like this:
$($('#foo tr')[rowIndex]).html('<td>i now contain even more stuff!</td>');
but best to use :eq
Try this
$('#foo > tr').eq(rowIndex).html('<td>i now contain even more stuff!</td>');
function manipulateRow(rowIndex) {
var $row = $('#foo tr:nth-child(' + rowIndex + ')');
...
}
See nth-child-selector.
here you go:
<table>
<tbody>
<tr><td>Foo</td></tr>
</tbody>
<tfoot>
<tr><td>footer information</td></tr>
</tfoot>
</table>
$("#myTable > tbody").append("<tr><td>row content</td></tr>");
heres another example inline editing:
function editRow(row) {
$('td',row).each(function() {
$(this).html('<input type="text" value="' + $(this).html() + '" />');
});
}

Jquery conditional statement

My html
<tr id="uniqueRowId">
<td>
<input class="myChk" type="checkbox" />
</td>
<td class="from">
<textarea class="fromInput" ...></textarea>
</td>
<td class="to">
<textarea ...></textarea>
</td>
</tr>
I have a table where each row is similar to the above with only one exception: not all rows will have textreas. I need to grab all rows that have textareas AND checkbox is not "checked".
Then I need to leaf through them and do some stuff.
I tried something like:
var editableRows = $("td.from .fromInput");
for (s in editableRows)
{
$s.val("test value");
}
but it didn't work.
1) how do I grab ONLY the rows that have checkboxes off AND have fromInput textareas?
2) how do I leaf through them and access the val() of both textareas?
I am sure this could be optimized, but I think it will work.
$("tr:not(:has(:checked))").each(function(i, tr) {
var from = $(tr).find("td.from textarea").val();
var to = $(tr).find("td.to textarea").val();
//now do something with "from" and "to"
});
See it working on jsFiddle: http://jsfiddle.net/RRPqb/
You can use this to select the rows:
$('tr', '#yourTable').has('input:checkbox:not(:checked)').has('textarea')
Live demo: http://jsfiddle.net/simevidas/Zk5EH/1/
As you can see in the demo, only the row that has a TEXTAREA element and a unchecked checkbox will be selected.
However, I recommend you to set classes to your rows: the TR elements that contain TEXTAREA elements should have a specific class set - like "directions". Then you could select those rows easily like so:
$('tr.directions', '#yourTable').each(function() {
if ( $(this).find('input:checkbox')[0].checked ) return;
// do your thing
});
$("tr:not(:has(:checked)):has(input.fromInput)")
Should be what you need. All the rows that don't have anything checked but that do have an input with the class 'fromInput'
If you want to loop through them to get the value of any textarea just extend your selector:
$("tr:not(:has(:checked)):has(textarea.fromInput) textarea")
Or as above if you want to be able to distinguish them:
$("tr:not(:has(:checked)):has(textarea.fromInput)")
.each(function() {
var from = $(this).find("td.from textarea").val();
var to = $(this).find("td.to textarea").val();
})
I don't know how much performance is a concern here, but if it is, then rather then writing a selector to find rows that contain a textarea you may find it helps to add a class to the row itself.
<tr class="hasTextarea">
Then you could alter your JQuery as so:
$("tr.hasTextarea:not(:has(:checked))")

JQuery's appendTo is very slow!

I have a html table that I reorder based on a CSV list of custom attribute values that I have for each table row. I am using the following function to do it:
for (var i = 0; i < arrCSV.length; i++)
{
$('#' + tableId)
.find('[fname = ' + arrCSV[i] + ']')
.eq(0)
.parents('tr')
.eq(0)
.appendTo('#' + tableId);
}
The table structure is:
<table>
<tr>
<td fname='f1'>something here</td>
</tr>
<tr>
<td fname='f2'>something here</td>
</tr>
</table>
The CSV could be something like this "f2, f1"
I find this is very very slow performing function. Any help in optimizing it is really appreciated.
EDIT:
Based on the article at http://www.learningjquery.com/2009/03/43439-reasons-to-use-append-correctly, one can achieve the greatest boost in performance by calling append only once with the html concatenated string. Can someone help in using this technique to my problem? I am not sure how to go about getting the s HTML in the for loop and appending it once.
I would suggest finding the elements as few times as possible. Store all the matching rows into a "hash" using the attribute value of interest as the key. Go through your CSV, pick the corresponding row out of the hash, push it into an array, then finally append the elements of the array to the table using the jQuery object previously found.
var table = $('#' + tableId);
var rowHash = {};
table.find('[fname]').each( function() {
rowHash[$(this).attr('fname')] = $(this).closest('tr');
});
var rows = [];
for (var i = 0; i < arrCSV.length; ++i)
{
var row = rowHash[arrCSV[i]];
if (row) {
rows.push(row);
}
}
$(rows).appendTo(table);
EDIT: This seems like a slight improvement to my previous code where I was appending each row to the table as it was found. I tested on a table with 1000 rows and it seems to take about 1sec to sort a table that needs to be completely inverted.
If you want to append html only once (like that learningjquery.com article), try following:
$(document).ready(
function()
{
var arrCSV = ['f2', 'f1'];
var tableId = 'mainTable';
var newTable = [];
for (var i = 0; i < arrCSV.length; i++)
{
var row = $('#' + tableId)
.find('[fname = ' + arrCSV[i] + ']')
.eq(0)
.parents('tr')
.eq(0);
newTable.push(row.html());
}
$('#' + tableId).html(newTable.join(''));
};
});
Live version: http://jsbin.com/uwipo
Code: http://jsbin.com/uwipo/edit
Though I personally feel that you should profile your code first and see if it's append which is slow OR that 'find' method call. I am thinking that for a huge table, using 'find method' to find a custom attribute could be slow. But again, there is no point in any guesswork, profile the code and find it out.
If the 'find' method is slow, will it be possible to use id attribute on td instead of giving custom attribute.
e.g.
<table>
<tr>
<td id='f1'>something here</td>
</tr>
<tr>
<td id='f2'>something here</td>
</tr>
</table>
Then your code to find the parent row could be as simple as:
('#' + arrCsv[i]).parent('tr')
EDIT: As pointed out by tvanfosson, this code assumes that arrCSV contains attribute for all the rows. The final table will only contain those rows which are present in arrCSV. Also, this code does not copy 'thead', 'tfoot' section from the original table, though it should be easy to write code which does.
You may have to rethink your algorithm.
Without changing the algorithm, a slight optimization would be:
var $table = $("#" + tableId);
for (var i = 0; i < arrCSV.length; i++)
{
$('[fname = ' + arrCSV[i] + ']:first',$table).closest('tr').appendTo($table);
}
Wait a second...
$('#' + tableId)
Get #myTable
.find('[fname = ' + arrCSV[i] + ']')
Find anything with an attribute of fname equal to i
.eq(0)
Give me the first item of the previous expression
.parents('tr')
Find the parents of type TR
.eq(0)
Give me the first in the previous expression
.appendTo('#' + tableId);
Add that TR to #myTable
Okay. Now that I've broken it down - are you duplicating a Table Row only? If so, the .append() isn't your problem, your choices of selectors is. To further compound my confusion here, the only tags with an attribute of fname are your TR's, so why are you going to their parents() and seeking out the first TR? You're basically asking for TR tags to be placed within TR tags - but that isn't what your Markup example shows.

Categories

Resources