rowspanされてて2行で一組なテーブルってよくあるじゃないですか。
それを動的にまるっと挿し替えたいときどうするか。

とりあえず試してみる

中の値だけ差し替えればいいじゃんとかは無しです。
そんなのちまちまやってたらキリがないですし、可搬性がありません。
やはりテンプレートから生成した要素でまるっと入れ替えたいものです。

上記のコード例では2行一組を想定し、検索用のキーとして組単位でdata-row-id属性を振りました。
この2行をjQueryでいっぺんに入れ替えようとしたら・・・

って一見思うじゃん?( ^ω^)
駄目なんだなこれが。tableをダンプしてみるとこうなってる。

まあ冷静に考えればfind条件が2箇所にヒットして、
結果の要素セットの中身は2個入ってるわけだから、eachしたら2回置換走るよねって単純な答えです。

新しいのを挿入して、古いの消せばいいじゃん?

それじゃあ手前に新しい行をツッコんでから古い方をremove()してやルルォ!って思うじゃないですか。

やったか!?・・・結果↓

そしてみんないなくなった。
結構引っかかる人多いんじゃないですかね。どうもinsertBefore()した時点でtraversingがひとつ進んで、
新しく追加された行が含まれた集合へと変化しています。

ならば、end()で巻き戻してやる!どやっ!

もう手遅れです。end()で戻ったとしても、traversingのキャッシュが更新されたことにより、
find(‘tr[data-row-id=”1″]’)の結果には追加した行が含まれてしまっています。なので最早無駄です。

手の打ちようがないですね。万事休す、長ったらしいコードを書かざるを得ないか…
とはなりません。jQueryに拘らなければ良いのです。

似て非なる要素セット達

find()結果の要素セットは、ネイティブのHTMLCollection(document.getElementsByTagName()などが返す)と検索結果セットが動的に変化することは似ていますが、
前者は後で動的に変化することはあっても、DOMツリーの変更がトリガーとなるわけではありません。
あくまでjQueryを利用したDOM操作係のメソッドが実行されることにより変化がもたらされます。

試しにjQuery.fn.find(), document.getElementsByTagName(),document.querySelector()
の3つのDOM検索系メソッドの挙動を確認してみます。tableやnewRows変数は引き続き先のを再利用します。

これの実行結果は以下のようになり、含まれているtr要素の変化を見てみることで、
HTMLCollection以外はDOMの直接操作による変化は起きないことがわかります。

結論:直接DOMに流し込め

つ・ま・り、新しい行の挿入をjQueryでやらなければいいのです。(それでも敢えて他の部分はjQuery使う)
ネイティブ実装のメソッドで手短に解決します。具体的には以下。

これにて一件落着。めでたし。
ちなみに、ネイティブJSだけでこう書いても同じことです。

結局言いたいこと

今回のようにjQueryだけでなんでもやろうとすると、返って苦労することが時折あります。
jQueryは初心者の足がかりとしては有用かもしれませんが、ES6が浸透してJSそのものが強力になってきた今、深く学ぼうとするならばjQueryではなくネイティブJSを極めましょう!です。