简体   繁体   中英

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

  • 1
  • 2 and
  • 4

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

  • 1 and
  • 4

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.

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>

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.

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 :)

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"]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM