innerHTMLプロパティに文字列を足しこむと、意図した表示にならない。 - JavaScript

innerHtmlプロパティに文字列を足しこむと、意図した表示にならない現象の紹介と対処法を紹介します。

現象の確認

以下のHTMLファイルを作成します。
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
  <style>
    table {
      border-collapse: collapse;
      border: 1px solid #717171;
    }

      table tr td {
        padding: 0.1rem 1rem 0.1rem 0.5rem;
        border: 1px solid #717171;
      }
  </style>
  <script type="text/javascript">
    window.onload = proc;
    function proc() {
      var header = ["ID","品名","価格","在庫数"];
      var item = [
        [1, "ぺんぎんクッキー", 340, 8],
        [2, "しろくまアイス", 240, 12],
        [3, "かるがもサブレ", 140, 6],
        [4, "ふくろうカステラ", 680, 3]
      ]

      var elem = document.getElementById("output");

      elem.innerHTML = "<table><thead>"

      elem.innerHTML += "<tr>";
      for (i = 0; i < header.length; i++) {
        elem.innerHTML += "<th>" + String(header[i]) + "</th>";
      }
      elem.innerHTML += "</tr></thead><tbody>";

      for (i = 0; i < item.length; i++) {
        elem.innerHTML += "<tr>";
        for (j = 0; j < item[i].length; j++) {
          elem.innerHTML += "<td>" + String(item[i][j]) + "</td>";
        }
        elem.innerHTML += "</tr>";
      }
      elem.innerHTML += "</tbody></table>";
    }
  </script>
</head>
<body>
  <h2>innerHtmlがうまく動作しないデモ</h2>

  <div id="output"></div>
</body>
</html>

解説

ページ読み込み時にproc関数を実行します。 ページ表示時のJavaScriptの実行の詳細はこちらの記事を参照してください。
window.onload = proc;

ヘッダの配列と、コンテンツの2次元配列を作成します。
  var header = ["ID","品名","価格","在庫数"];
  var item = [
    [1, "ぺんぎんクッキー", 340, 8],
    [2, "しろくまアイス", 240, 12],
    [3, "かるがもサブレ", 140, 6],
    [4, "ふくろうカステラ", 680, 3]
  ];

getElementByIdメソッドを呼び出し、id="output" のDOM要素を取得します。
  var elem = document.getElementById("output");

取得した要素のinnerHTMLプロパティに出力したいタグの文字列を足しこんでいきます。
tableタグを出力して、ヘッダの値とコンテンツを表組してページに表示します。
  elem.innerHTML = "<table><thead>"

  elem.innerHTML += "<tr>";
  for (i = 0; i < header.length; i++) {
    elem.innerHTML += "<th>" + String(header[i]) + "</th>";
  }
  elem.innerHTML += "</tr></thead><tbody>";

  for (i = 0; i < item.length; i++) {
    elem.innerHTML += "<tr>";
    for (j = 0; j < item[i].length; j++) {
      elem.innerHTML += "<td>" + String(item[i][j]) + "</td>";
    }
    elem.innerHTML += "</tr>";
  }
  elem.innerHTML += "</tbody></table>";

表示結果

上記のHTMLファイルをWebブラウザで開きます。下図のページが表示されます。
tableタグを出力しているロジックですが、コンテンツが表組されません。


bodyのタグ構造は以下になります。trタグやtdタグが無くなっています。
<body>
  <h2>innerHtmlがうまく動作しないデモ</h2>

  <div id="output"><table><thead></thead></table>ID品名価格在庫数1ぺんぎんクッキー34082しろくまアイス240123かるがもサブレ14064ふくろうカステラ6803</div>

</body>

原因

innerHTMLプロパティに値を順次代入した場合、代入した直後にタグの整合性の検証が実行されます。その際に、タグが補完されるため、意図した表示にならないです。

innerHTMLプロパティへの最初のtableタグの代入直前にブレークポイントを置き、innerHTMLの値を確認します。この時は空文字列になっています。


innerHTMLプロパティにtableタグ、theadタグを代入すると、タグの検証が実行され、すぐに閉じタグが自動で補完されます。innerHTMLには <table><thead></thead></table> の文字列が設定されます。その後に trタグをinnerHTMLプロパティに代入していますが、tableタグが閉じられているため、タグは無視されます。

対処法

innerHTMLプロパティに順次文字列を設定せず、変数にすべてのHTMLタグを代入した後、 変数の文字列を一度にinnerHTMLプロパティに代入することで、正しくHTMLタグを表現できます。

プログラム例

コード

以下のHTMLファイルを作成します。
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
  <style>
    table {
      border-collapse: collapse;
      border: 1px solid #717171;
    }
      table tr th {
        padding: 0.1rem 1rem 0.1rem 0.5rem;
        border: 1px solid #717171;
        font-size:0.8rem;
      }

      table tr td {
        padding: 0.1rem 1rem 0.1rem 0.5rem;
        border: 1px solid #717171;
      }
  </style>
  <script type="text/javascript">
    window.onload = proc;
    function proc() {
      var header = ["ID","品名","価格","在庫数"];
      var item = [
        [1, "ぺんぎんクッキー", 340, 8],
        [2, "しろくまアイス", 240, 12],
        [3, "かるがもサブレ", 140, 6],
        [4, "ふくろうカステラ", 680, 3]
      ];
      var elem = document.getElementById("output");

      var htmlDoc;

      htmlDoc = "<table><thead>"

      htmlDoc += "<tr>";
      for (i = 0; i < header.length; i++) {
        htmlDoc += "<th>" + String(header[i]) + "</th>";
      }
      htmlDoc += "</tr></thead><tbody>";

      for (i = 0; i < item.length; i++) {
        htmlDoc += "<tr>";
        for (j = 0; j < item[i].length; j++) {
          htmlDoc += "<td>" + String(item[i][j]) + "</td>";
        }
        htmlDoc += "</tr>";
      }
      htmlDoc += "</tbody></table>";

      elem.innerHTML = htmlDoc;
    }
  </script>
</head>
<body>
  <h2>innerHtmlでTableタグを出力するデモ</h2>

  <div id="output"></div>
</body>
</html>

解説

htmlDoc変数を宣言します。
  var htmlDoc;

htmlDoc変数にタグや値の文字列を代入します。
  htmlDoc = "<table><thead>"

  htmlDoc += "<tr>";
  for (i = 0; i < header.length; i++) {
    htmlDoc += "<th>" + String(header[i]) + "</th>";
  }
  htmlDoc += "</tr></thead><tbody>";

  for (i = 0; i < item.length; i++) {
    htmlDoc += "<tr>";
    for (j = 0; j < item[i].length; j++) {
      htmlDoc += "<td>" + String(item[i][j]) + "</td>";
    }
    htmlDoc += "</tr>";
  }
  htmlDoc += "</tbody></table>";

htmlDoc変数の値をinnerHTMLプロパティに代入します。
  elem.innerHTML = htmlDoc;

実行結果

上記のHTMLファイルをWebブラウザで表示します。下図のページが表示されます。 配列変数の値が表組されて表示されました。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2023-02-16
iPentec all rights reserverd.