简体   繁体   中英

How to get the closest parent OR sibling that matches a selector?

Given a table:

<table border>
    <tr>
        <th rowspan=3>H1</th>
        <td>1</td>
    </tr>
    <tr>
        <td>2</td>
    </tr>
    <tr>
        <td>3</td>
    </tr>
    <tr>
        <th rowspan=3>H2</th>
        <td>21</td>
    </tr>
    <tr>
        <td>22</td>
    </tr>
    <tr>
        <td>23</td>
    </tr>
</table>

Let's suppose we have an event on the 'td' that should search the closest 'th' (trasversing the DOM upwards). For instance, when clicking on 1, 2 or 3, it should return H1. When clicking on 21,22,23, it should return H2.

Any ideas?

The HTML structure you're checking can cover different branches, so you need to write a recursive function to check for sibling th elements and if there are none, children of the closest tr element's siblings. Try this:

$('td').click(function() {
    alert(findTh($(this).closest('tr')));
});

function findTh($row) {
    var $th = $('th', $row), 
        $prevRow = $row.prev('tr');

    if ($th.length) {
        return $th.text();
    }
    else if ($prevRow.length) {
        return findTh($prevRow);
    }
    else {
        return '';
    }
}

Example fiddle

Select siblings and original element, then use closest.

$(this).siblings().addBack().closest("th");

if one of the siblings matches the selector, it'l select the first one, else it'l traverse up the tree and return the first that matches.

A plugin might be overkill, but this works:

http://jsfiddle.net/eVpHG/

$.fn.myTh = function () {
    var $elem = this.first();    

    var $th = $elem.siblings('th');    
    if ($th.length)
        return $th;

    else
        return $elem.parent('tr').prev('tr').children('th');

};

What about this:

$('td').click(function () {
    if ($(this).parent().has('th').length > 0) {
        $(this).parent().find('th').css('background', 'red');
        //alert('first row!');
    } else {
        $(this).parent().prevAll('tr').has('th').first().find('th').css('background', 'red');
    }
})

Basicially i first check if you have selected the first row, the row that contains the <th> .
If that is not the case i'll search for all previous <tr> elements (Going to top of DOM structure). Whenever one has a <th> element it will be in the .prevAll query. I'll select the first one that was selected.
Now we select the <th> in the selected <tr> .

I hope it's not "over the top" ^^

jsFFiddle

You could use

$(this).parent().prevAll('tr').add($(this).parent()).has('th').last().find('th');

Demo

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