Search code examples
jqueryinsertafter

Can I modify a selector used as param of insertAfter via other jQuery methods?


I'd like to move the second tr parent of a selected element, to go after the second tr parent of another selected element. I can do this a number of ways in 2 lines but can I do it in one?

Due to a terrible CMS that nests a bunch of elements and gives ID attributes for only a few, here's my starting HTML structure:

<tr>
    <td>
        <table>
            <tbody>
                <tr>
                    <td>
                        <div id="element1">
                            [...]
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
    </td>
</tr>
<tr>
    <td>
        <table>
            <tbody>
                <tr>
                    <td>
                        <div id="element2">
                            [...]
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
    </td>
</tr>
<tr>
    <td>
        <table>
            <tbody>
                <tr>
                    <td>
                        <div id="element3">
                            [...]
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
    </td>
</tr>

I have a much larger number than three of this repeating pattern, of course, but that's the structure. I need to rearrange these outer tr elements. I have tried this:

jQuery("div#element3").parents("tr").eq(1).detach().insertAfter("div#element1").parents("tr").eq(1);

but when that runs, it behaves as if I've typed:

jQuery("div#element3").parents("tr").eq(1).detach().insertAfter("div#element1");

Is there not a way, in one line, to do an insertAfter on not the element selected by its selector parameter, but rather on an element selected by applying additional methods to the result of that selector? Doubling up the parens around the selector plus the following methods to try to group them as the target of the operation does not work.

Obviously I can solve the problem by declaring a var to hold ("div#element1").parents("tr").eq(1), and pass that as the argument to insertAfter--but I can't believe I can't do this in one line of code, and since I have to do a ton of these manipulations, in an arbitrary, non-loopable way, I'd for sure prefer one line.

Thanks!


Solution

  • You need to put the parents traverse of the second div inside the insertAfter() and make it a new jQuery object

    Can also remove the detach(). That will be done automatically since an element can't exist in 2 places without being cloned.

    jQuery("div#element3").parents("tr").eq(1).detach()
         .insertAfter(jQuery("div#element1").parents("tr").eq(1));
    

    Personally I would break this up. Getting it all on one long line vs making it readable is worth extra lines

    Something like:

    var $toMove = jQuery("div#element3").parents("tr").eq(1);
    var $target = jQuery("div#element1").parents("tr").eq(1);
    $target.after($toMove)
    

    One final suggestion would be that if you have multiple traverses like this to do would be try to add some classes on page load to make traversals simpler later on

    Then you can do something like:

    var $toMove = jQuery("div#element3").closest("tr.main-rows");
    var $target = jQuery("div#element1").closest("tr.main-rows");
    $target.after($toMove)