Devraj Gadhavi
Devraj Gadhavi

Reputation: 3611

jQuery: select tr having all td matching the filter criteria dynamically

Title might be a bit confusing, but this is the best I could come up with.

I need to find all tr elements which contains td elements matching the filter criteria provided.

Here is my sample,

<tr class="row" id="1">
    <td class="philips">PHILIPS</td>
    <td class="h4">H4</td>
    <td class="lamp">Lamp<td>
</tr>
<tr class="row" id="2">
    <td class="philips">PHILIPS</td>
    <td class="h5">H5</td>
    <td class="bulb">Bulb<td>
</tr>
<tr class="row" id="3">
    <td class="neglin">NEGLIN</td>
    <td class="w5w">W5W</td>
    <td class="tube">Tube<td>
</tr>
<tr class="row" id="4">
    <td class="philips">PHILIPS</td>
    <td class="h4">H4</td>
    <td class="bulb">Bulb<td>
</tr>
<tr class="row" id="5">
    <td class="osram">OSRAM</td>
    <td class="hb3">HB3</td>
    <td class="tube">Tube<td>
</tr>
<tr class="row" id="6">
    <td class="neglin">NEGLIN</td>
    <td class="w5w">W5W</td>
    <td class="lamp">Lamp<td>
</tr>

If I pass filter[0] as 'phillips', the result return tr with id

Then if I pass second filter; filter[1] as 'h4', the result should be filtered down to

I have tried this question.

Which has this answer.

$('tr')
.has('td:nth-child(1):contains("Audi")')
.has('td:nth-child(2):contains("red")')
.doSomeThing();

But, I want my filters to be applied dynamically. How would I be able to insert a 3rd has function?

I don't want to go the if-else or switch-case way, if this is possible with out them.

Upvotes: 1

Views: 1077

Answers (4)

Red
Red

Reputation: 26

You can try this.

<script type="text/javascript">
    $(document).ready(function () {
        var result =  filter([".philips", ".h4"]);
        alert(result);
        var result_2 = filter([".philips"]);
        alert(result_2);
    });

    function filter(params) {
        var select = "tr";

        for (var i = 0; i < params.length; i++) {
            select += ":has(" + params[i] + ")";
        }

        return $(select).map(
              function () { 
                  return $(this).attr('id');
              }
        ).get();
    }
</script>

Upvotes: 1

rism
rism

Reputation: 12142

You can supply your filter as a string:

var filter = ".philips, .h4";

$("tr").has("td").has(filter).map(function() { return this.id; });  
// returns ["1", "2", "4"]

and if you want the elements then obviously leave the map off:

  $("tr").has("td").has(filter);
  // returns array of <tr>

Edit: Just noticed you want recursive filtering so change the filter to use sibling selector ~.

var filter = ".philips ~ .h4";
// returns ["1", "4"]

So if you want a third level then just:

var filter = ".philips ~ .h4 ~ .bulb";
// returns ["4"]

Upvotes: 0

Ward D.S.
Ward D.S.

Reputation: 558

if you have an array of filters needed, iterate that array and pass the filter string to the has?

var filters = ['PHILIPS', 'H4', 'Bulb']
var result = $('tr');
for(var i = 0; i < filters.length; i++){
    var nchild = i+1;
    result = result.has('td:nth-child('+nchild+'):contains("+'filters[i]'+")');
}

edit to your needs of course, but this way you can take user input, compile that into the needed array and then iterate whatever is in the array to filter down results.

Upvotes: 1

Filip
Filip

Reputation: 1244

You should wrap the $.has() into a separate function (I've just used jquery's easy extensions supports) which will expose the usage as a composite function chain via javascript's syntax...

$( document ).ready(function() {

        $('tr')
        .nthFilter('td:nth-child(1):contains("PHILIPS")')
        .nthFilter('td:nth-child(2):contains("H4")')
        .nthFilter('td:nth-child(3):contains("Bulb")')
        .css("background-color", "red");
});

jQuery.fn.extend({
  nthFilter: function(filter) {
    return $(this).has(filter);    
  }
});

I've put together a small jsfiddle for you to fiddle with :)

Upvotes: 0

Related Questions