Large Display Size Middle Display Size Small Display Size
印刷用 概要 キーワード 著者

outerHTML の落とし穴 (2個あり)


JavaScript の outerHTML プロパティについての話題です。

あまり使わない outerHTML プロパティですが、このプロパティには 2個の落とし穴があります。

  1. 「要素に outerHTML をセットする際は親ノードが必要」
  2. 「outerHTML において createElement() と getElementById() のオブジェクトは異なる」

この2点について探っていきたいと思います。


なお、以下のようなHTML要素を作る場合に、

<div>テストです</div>

innerHTML は赤い部分を指定するものであり、outerHTML は青い部分も含めて指定するものです。

要素に outerHTML をセットする際は親ノードが必要

innerHTML と比較したいので、まずはよく使う innerHTML の、いつものプログラムを見てみましょう。

HTML の要素を操作しようというとき、innerHTML を多用すると思います。

具体的な流れは、もともとのページにはないHTML要素を document.createElement() で作成して、その innerHTML に内容(HTML) を代入、そして document.body.appendChild() します。

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title></title>
<script>
function onloadx() {
//新しい要素を作成
var div = document.createElement( "DIV" );
div.innerHTML = "テストです";
document.body.appendChild( div );
}
</script>
</head>
<body onload="onloadx()">
この次に追加されます。
</body>
</html>

 新しいウィンドウで実行  [小WINで表示]

「新しいウィンドウで実行」ボタンを押すと、「テストです」というDIV要素が追加で表示されます。


その流れで innerHTML とよく似た outerHTML を使う場合、単語の inner を outer に書き換えて、その代入の内容を div タグをくくるように変更すれば良い、と思うでしょう。

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title></title>
<script>
function onloadx() {
//新しい要素を作成
var div = document.createElement( "DIV" );
div.outerHTML = "<div>テストです</div>";
document.body.appendChild( div );
}
</script>
</head>
<body onload="onloadx()">
この次に追加されます。
</body>
</html>

 新しいウィンドウで実行  [小WINで表示]

しかし、結果はその要素が追加されません。


これは以下のどのブラウザでも同じ動きとなりました。(ただし Firefox のみエラーを出しませんでした)

ブラウザコンソールに表示したエラー
Firefox
ver 49.0.1
エラーなし
Google Chrome Uncaught NoModificationAllowedError:
Failed to set the 'outerHTML' property on 'Element':
This element has no parent node.
(修正は許可されませんエラー:
『要素』の'outerHTML'プロパティにセットする際失敗した:
この要素は親ノードを持っていない。)
Internet Explorer SCRIPT5022: NoModificationAllowedError
(修正は許可されませんエラー)
Edge SCRIPT5022: NoModificationAllowedError
(修正は許可されませんエラー)

いずれも Windows10 のブラウザです。

いずれのエラーメッセージも、プログラム中の、div.outerHTML = ...; の行についてのエラーです。

この Google Chrome のメッセージにある通り、「親要素がない」ことが不具合の原因のようです。

innerHTML ではそんなエラーは出なかったのに。

(ちなみに私がメインで使っているのは Firefox ですが、Google Chrome のみ「次にどうすればいいか」というのがわかるエラーメッセージで好感がありますね)


では appendChild() を先にして、outerHTML の代入を後にしてみましょう。

そうすれば親要素がある状態での outerHTML 代入となります。

(apendChild() の行をカットして、outerHTML 代入の行の前に貼り付け)

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title></title>
<script>
function onloadx() {
//新しい要素を作成
var div = document.createElement( "DIV" );
document.body.appendChild( div );
div.outerHTML = "<div>テストです</div>";
ここにあったものは 削除しました
}
</script>
</head>
<body onload="onloadx()">
この次に追加されます。
</body>
</html>

 新しいウィンドウで実行  [小WINで表示]

すると、DIV要素「テストです」が表示され、正しく動きました。


つまり、innerHTML は親要素が不要ですが、outerHTML では親要素が必要ということです。

私も情報がないのでよくわかりませんが、outerHTML のように、タグそのもの や タグ内の属性 は、親要素と密接に関係しているので、単独では設定できない、ということでしょうか…。

ともかく outerHTML への代入時は親要素の存在を気にしましょう。


outerHTMLにおいて createElement() と getElementById() のオブジェクトは異なる

それから、上記からの流れで以下についても注意です。


createElement() で作成したオブジェクトと、document.getElementById() で取得したオブジェクトは同じオブジェクトに思えて実は「異なる」ということです。

outerHTML の div タグに id を付けて、比較できるようにしてみると、

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title></title>
<script>
function onloadx() {
//新しい要素を作成
var div = document.createElement( "DIV" );
document.body.appendChild( div );
div.outerHTML = "<div id='testID'>テストです</div>";

alert( div == document.getElementById( "testID" ) );
}
</script>
</head>
<body onload="onloadx()">
この次に追加されます。
</body>
</html>

 新しいウィンドウで実行  [小WINで表示]

結果はどのブラウザでも false です。

createElement() で要素を作成したのだし、getElementById() で同じはずの要素を取り出したのだから、2つのオブジェクトは同じだと思いたいのですが、異なります。


これは innerHTML で同じことをすると 結果は true なので、outerHTML特有の現象と言えそうです。(私のやっていることに間違いがなければ。)

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title></title>
<script>
function onloadx() {
//新しい要素を作成
var div = document.createElement( "DIV" );
document.body.appendChild( div );
div.innerHTML = "テストです";
div.id = "testID";

alert( div == document.getElementById( "testID" ) );
}
</script>
</head>
<body onload="onloadx()">
この次に追加されます。
</body>
</html>

 新しいウィンドウで実行  [小WINで表示]

結果はどのブラウザでも true です。


これについて何が問題かというと、createElement() で作成してなおかつ outerHTMLに代入を行ったオブジェクトは、その後いくら操作してもページの内容は変更されないということです。

(そのオブジェクトはまるで appendChild() と outerHTML の代入でしか機能していないかのよう)

操作するときは、一度 getElementById() などで取得しなおす必要があります。


以上の通り、あまり使わない outerHTML には落とし穴が 2個あります。

あまり使わないゆえに、みんなその穴に落ちると思われるので、要注意です。

ページ制作 homepage6047


ページの上端へ (もくじ開く)