Edited at

フロントエンドド素人が、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の動きをしっかり理解することが大切ですね。


参考