views:

692

answers:

3

Hello everyone,

I made a little search-function with javascript to look for a string in a table: There are "tr"s that simply contain a number as an id and there are "tr"s that contain "childNode+idOfParentNode" as an id (e.g.:

<tr id="1"> ... </tr>
<tr id="childNode1"> ... </tr>

Now I want to look through the table, see if a giving string or part of it matches the content of the parent-"tr". If that is not the case I want the parent-"tr" and its childNode-"tr"s to be hidden (or collapsed). And I want them being shown if the string or part of it matches. Here is my function:

// inputFieldId := Id of the inputField that contains the search-String
// tableId := Id of the table to be searched
function searchTable( inputFieldId, tableId ){
    var inputField = document.getElementById( inputFieldId );
    var input = inputField.value.toUpperCase();
    var countRows   = jQuery( '#' + tableId + ' tr' ).length;
    jQuery('#loader').css( "visibility", "visible" );
    var hideChildren = false;
    var childId = -1;
    var parentId = -1;

    for( var i = 1; i <= countRows; i++ ){
        var trsId = jQuery('#' + tableId + ' tr:nth-child('+i+')' ).attr('id');
        // I am only looking for <tr> that are not "childnodes"
        if( trsId.indexOf( "childNode") == -1 ){
            var firstTd = jQuery('#' + tableId + ' tr:nth-child('+i+') td:nth-child(1)' );
            var firstTdValue = firstTd.text();
            if( firstTdValue.indexOf( input ) == -1 ){
                hideChildren = true;
                childId = trsId;
                parentId = i;
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).children('td').css("visibility", "collapse");
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).css("visibility", "collapse");
            }
            else{
                hideChildren = false;
                childId = trsId;
                parentId = i;
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).children('td').css("visibility", "visible");
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).css("visibility", "visible");
            }
        }
        else{
            childNodeId = "childNode"+childId;
            if( hideChildren && trsId == childNodeId && parentId > -1 ){
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).children('td').css("visibility", "collapse");
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).css("visibility", "collapse");
            }
            else{
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).children('td').css("visibility", "visible");
                jQuery('#' + tableId + ' tr:nth-child('+i+')' ).css("visibility", "visible");
            }
        }
    }
    jQuery('#loader').css( "visibility", "hidden" );
}

Seriously, this works fine, but it takes FOREVER!!! especially if it is a larger table, so I was wondering if someone saw a way to make my function faster and more efficient.

Thnx in advance :)

=========================================================================

EDIT: I made it work ... it now looks like this and works wonderfully :)

function searchTable( inputFieldId, tableId ){
    jQuery('#loader').show();
    var input = jQuery('#'+inputFieldId).val().toUpperCase();
    var parentId = -1

    jQuery('#' + tableId + ' tr').each( function(i) {
        var thiss = jQuery(this);
        var showP = false;
        var showC = false;
        if (thiss.attr('id').indexOf('child') < 0) { // parent
            parentId = thiss.attr('id');
            showP = !(thiss.find('td:first').text().indexOf( input ) < 0);
            thiss.toggle( showP );
        }
        else{ // childNode
            var childId = "childNode"+parentId;
            var parent = jQuery('#'+tableId+' tr#'+parentId+':visible').length;
            showC = !(thiss.attr('id') == childId && parent < 1);
            thiss.toggle( showC );
        }        
    });
    jQuery('#loader').css( "visibility", "hidden" );
}

Thank you :)

+1  A: 

1) Cache the selector that you create multiple times. Then use the variable from then on in.

var $rows = jQuery('#' + tableId + ' tr:nth-child('+i+')' );

$rows.children()...

2) to get direct children you can use '>' in your selector

 var $rows = jQuery('#' + tableId + '>tr:nth-child('+i+')' );
redsquare
A: 
var rowsCache = null;
function searchTable( inputFieldId, tableId ){

    var input = String(jQuery("#inputFieldId").val()).toUpperCase();

    if (rowsCache==null)
     rowsCache = jQuery( '#' + tableId + ' tr');

    jQuery('#loader').css( "visibility", "visible" );

    //if there are many rows is faster --
    //for(var i = (countRows-1); i >= 0; i--) {

    jQuery(rowsCache).each(function() {
     if ((jQuery(this).html().indexOf(input)!=-1)
     {
      ...
     }
    });
    jQuery('#loader').css( "visibility", "hidden" );
}
andres descalzo
+1  A: 

It would be easier if the parents (and children) had classes identifying them as such, but you can get by with the ids if need be. I'm using $ instead of jQuery, but you can change that back if you need to.

// inputFieldId := Id of the inputField that contains the search-String
// tableId := Id of the table to be searched
function searchTable( inputFieldId, tableId ){
    var input = $('#' + inputFieldId).text().ToUpperCase();

    $('#loader').show();

    $('#' + tableId + ' tr').each( function(i) {
         var $this = $(this);
         var show = false;
         //  if ($this.hasClass('parent')) {  // would be nice
         if ($this.attr('id').indexOf('child') < 0) { // parent
             // note that text() here is the combined texts of all tds
             // adjust with :first if you really want to check only the first
             show = !($this.find('td').text().indexOf( input ) < 0);
         }
         $this.toggle( show );
    });

    $('#loader').hide();
}
tvanfosson
with a little tugging here and a tagging there I made it work ... THNX :)
doro
oh yeah, this dollar-sign never works with me which why I had to change some things, I have no clue what I am doing wrong :(
doro
Are you trying to combine frameworks? If you use Prototype (or Dojo, etc.) and jQuery at the same time you need to set up jQuery using noConflict, like so var $j = jQuery.noConflict(), then you can use $j instead of jQuery everywhere.
tvanfosson
htnx a lot ... i tried it and it works!!! :) awesome! but i dun see where it colides as i am only using jquery and my own functions which themselves use jquery ...
doro