Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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の動きをしっかり理解することが大切ですね。

参考

LemonmanNo39
強くなりたい。ただそれだけです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away