0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

insertadjaceHTMLで二次元リストを表示しようとして失敗したこと

Last updated at Posted at 2021-04-07

#概要
Djangoのテンプレートの開発において、2次元リストのデータを表示しようとしたが手こずったのでその備忘録です。

自分のフロントエンド側の習熟度は素人に毛が生えている程度です。
早くボーボーになりたい。

#目的
・フロントエンド側に2次元リストの情報を表示する
・ユーザが操作→リストの内容が変更する
・すでにデータが表示されてる場合は内容を一新する

以下、ユーザーが部活を選択したときに、所属する生徒のIDと名前を表示するものを想定して記述します。

#達成に必要なもの/知識
タグの「table」「tr」「th」「td」の知識
insertAdjacentHTML()

以下はhtmlのぼんやりとしたイメージ

test.html
<table>
  <!-- リストのヘッダー -->
  <tr>
    <th>項目1</th>
    <th>項目2</th>
  </tr>

  <!-- データを挿入する部分-->
  <div id="replace-data">
    <tr>
      <td>データ1</td>
      <td>データ2</td>
    </tr>  
  <div>

#試作コード

test.html
<table id="classmate-club">
  <tr>
    <th>生徒</th>
    <th>部活</th>
  </tr>
</table>

例えばブラウザで「ラグビー部」をユーザが選択したときに以下のようなhtmlを出力できれば成功、などと思っていました。

test.html
<table id="classmate-club">
  <tr>
    <th>生徒ID</th>
    <th>生徒名</th>
  </tr>

  <!-- 要素生成部分 -->
  <tr>
    <td>1</td>
    <td>稲垣啓太</td>
  </tr>
  <tr>
    <td>2</td>
    <td>ジョナサン・ジョースター</td>
  </tr>
  <!-- -- -->
  
</table>

・バックエンドからユーザがクリックした生徒の名前とクラブ名が渡される
・「tr」「td」をhtmlに生成する(tdに生徒の情報を入れる)
・差し込んだ「tr」がすでにある場合は事前に削除する
 (どんどん増えていくので)

test.js

//バックエンドから渡されたデータが入っていると仮定
classmate = object()

// テーブルタグの要素をidで取得
var test_table = document.getElementById('classmate-club');

// 差し替えデータが一つでもある場合は削除する
var l_tr = document.getElementsByClassName('class-replace-data');
if(l_tr){
  for(i=0; i<l_tr.length; i++){
    l_tr[i].remove();
  }
}

// データ挿入
for(i=0; i<classmate.length; i++){
  // テーブル内の要素の最後にtrの要素を挿入
  test_table.insertAdjacentHTML('berforeend', '<tr id="id-replace-tr-"' + String(i) + ' class="class-replace-data">')

  // trの要素を取得  
  var test_tr = document.getElementById('id-replace-tr-' + String(i));

  // trの要素にtdをデータと共に挿入
  test_tr.insertAdjacentHTML('berforeend', '<td>' + classmate['id'] + '</td>')
  test_tr.insertAdjacentHTML('berforeend', '<td>' + classmate['name'] + '</td>')
}

上記のやり方で挿入されるtrの親にはtbodyが生成される。
そのため空のtbodyがどんどん生み出され、要素の削除もうまくいかない。

#沼ったポイント
・データの挿入部分をまとめて削除するときに便利だと思いid付きのdivで括ったがしかし
・insertAdjacentHTMLでtableの子階層のdivにtrを挿入できなかった
 →tableの子としてなら挿入できた
 consoleにエラーが表示されないため原因が明確ではないが、多分table/tr/tdの構造を崩してはいけない規則みたいなものがあるという認識で勝手に落ち着いている
 
・挿入したtrを挿入するときtbodyが自動で生成される

#解決策
element.innerHtml
element.insertAdjacentHTML()

ではなく
jqueryのapeend() またはprepend()を使用する。
今回はprependを使用する。

test.js

//バックエンドから渡されたデータが入っていると仮定
classmate = {object}

// 差し替えデータが一つでもある場合は削除する
$('table'#classmate-club tbody *').remove();

// データ挿入
for(i=0; i<classmate.length; i++){
  // テーブル内の要素の最後にtrの要素を挿入
  var str = '';
  str += '<tr>';
  str += '   <td>' + classmate[i]['id'] + '</td>';
  str += '   <td>' + classmate[i]['metric'] + '</td>';
  str += '</tr>';
  $(' table tbody').prepend(str);
}

これでオブジェクトを2次元リスト形式で自由に差し替え可能になる。
問題の原因だったtbodyはちゃんと削除され、データ差し替えが正常に行える。
おそらくelement.insertAdjacentHTML()を使ってもうまくいく手法があるのだろうが、多分こちらの方がシンプルにまとまる。

#さいごに
つまづいて解決策を調査しているときに視野が狭くなりがちな癖を直そうと思いました。
フロントサイドの勉強中なのでもっといい方法を教えて頂けたら幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?