JavaScript
dom

フロントエンドド素人が、JavascriptでDOM操作をして、子要素を消そうとしてあれ?ってなった話

はじめに

SQLの実行結果によって、HTML要素を削除したり、追加しているときに気づいた話を自分用メモとして残します。
もしかしたら勘違いしていることがあるかもしれないので、その際にはご指摘いただけると幸いです。

早速ですが以下の例、なんで子要素、つまり「太郎元気です!」が削除されず、どう消すのかわかりませんでした。

【HTML構成】

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h2>元気ですか~!</h2>
    <div id="parentObj">
      <p id = "childObj">太郎元気です!</p>
      <p id = "nextChildObj">二郎元気です!</p>
    </div>
  </body>
</html>

【Javascript構成】

const getParentObj = document.getElementById("parentObj");
const getChildObj = document.getElementById("childObj");

if(getParentObj.removeChild(getParentObj.firstChild)){
  alert("削除成功"); // 条件文は通るが、実際に太郎元気です!は消されてない。
}
else{
  alert("削除失敗");
}

直接子要素にアクセスしてやれば話は早いですが、子要素にidが振られていなかったときに大変です。
適当にwhile文を回して全部消して、削除したくない子要素だけ復活させるなんてやったら手間ですし、無駄な処理です。

結論

はじめに、でお話したHTML構成だと、直接子要素指定する or whileで全削除からの必要子要素のみ復活以外の方法では、以下のようにするしかないと思います。

const getParentObj = document.getElementById("parentObj");
const getChildObj = document.getElementById("childObj");
const childCount = getParentObj.childElementCount;

for(var i = 0; i < childCount; i++){
  getParentObj.removeChild(getParentObj.firstChild);
}

具体的説明

しかし、以下の例で条件文が通ってしまうことに違和感があり、原因を探ったところわかりました。

const getParentObj = document.getElementById("parentObj");
const getChildObj = document.getElementById("childObj");

if(getParentObj.removeChild(getParentObj.firstChild)){
  alert("削除成功"); // 条件文は通るが、実際に太郎元気です!は消されてない。
}
else{
  alert("削除失敗");
}

消えてないのではなく、消える対象を勘違いしているだけ

以下の例、本当は消す対象がないだけで、実行的にはうまくいっているんです。

const getParentObj = document.getElementById("parentObj");
const getChildObj = document.getElementById("childObj");

if(getParentObj.removeChild(getParentObj.firstChild)){
  alert("削除成功"); // 条件文は通るが、実際に太郎元気です!は消されてない。
}
else{
  alert("削除失敗");
}

というのも、HTML構成を少し変化させてみてみます。

【変化後のHTML構成】

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h2>元気ですか~!</h2>
    <div id="parentObj">
      三郎だって元気だよ。
      <p id = "childObj">太郎元気です!</p>
      <p id = "nextChildObj">二郎元気です!</p>
    </div>
  </body>
</html>

【Javascript構成】

const getParentObj = document.getElementById("parentObj");
const getChildObj = document.getElementById("childObj");

if(getParentObj.removeChild(getParentObj.firstChild)){
  alert("削除成功"); // 条件文は通り、三郎だって元気だよ。が削除されました!
}
else{
  alert("削除失敗");
}

ここで、親要素の内部に書かれた情報だけ削除されているのが、ブラウザのコンソールなどで調べればお分かりいただけると思います。

つまり、removeChild(getParentObj.firstChild)は、いきなり子要素に着目するのではなく、親要素を参照した後に、子要素のアクセスをしていることがわかりました。

おまけに

以下のようにやると、idが付けられていない要素の削除もできます。

【おまけのHTML構成】

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <h2>元気ですか~!</h2>
    <div id="parentObj">
      <p>太郎元気です!</p>
      <p>二郎元気です!</p>
    </div>
  </body>
</html>

【おまけのJavascript構成】

if(getParentObj.removeChild(getParentObj.firstElementChild.nextElementSibling)){
  alert("削除成功"); // 条件文は通り、二郎元気です!が削除されました!
}
else{
  alert("削除失敗");
}

最後に

すごく単純作業ですが、これに小一時間近くとられたので、メモしました。
removeChildの動きをしっかり理解することが大切ですね。

参考