質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.61%

JavaScriptで作るhtmlのtableをソート可能にしたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 96

前提・実現したいこと

JavaScriptで組み上げたhtmlのtableで作った表をソート可能にしたいです。
「tablesorter」を使っています。
https://mottie.github.io/tablesorter/docs/

発生している問題・エラーメッセージ

それらしきエラーはコンソールにも出ていません。
表自体は意図通りに作成表示されますが、
表示されるはずの三角マークは無く、その辺りをクリックしても全く無反応です。

historyListDivision関数から、historyListDivisionHeader関数を呼んでいます。

該当のソースコード

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

        <!-- ▼▼▼▼▼▼▼ 表のソートをするために要る ▼▼▼▼▼▼▼ -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.min.js"></script>
        <style>
            .tablesorter th{
                position: relative;
                cursor: pointer;
                text-align: left;
            }
            .tablesorter th::before, .tablesorter th::after{
                content: '';
                position: absolute;
                z-index: 2;
                right: 7px;
                width: 0;
                height: 0;
                border: 4px dashed;
                border-color: #333 transparent;
                pointer-events: none;
            }
            .tablesorter th::before{
                border-bottom-style: solid;
                border-top: none;
                top: 30%;
            }
            .tablesorter th::after{
                border-top-style: solid;
                border-bottom: none;
                bottom: 30%;
            }
            .tablesorter th.tablesorter-headerAsc:after{
                border: none;
            }
            .tablesorter th.tablesorter-headerAsc:before{
                top: 50%;
                transform: translateY(-50%);
                -webkit-transform: translateY(-50%);
            }
            .tablesorter th.tablesorter-headerDesc:before{
                border: none;
            }
            .tablesorter th.tablesorter-headerDesc:after{
                top: 50%;
                transform: translateY(-50%);
                -webkit-transform: translateY(-50%);
            }
            .tablesorter th.sorter-false:before, .tablesorter th.sorter-false:after{
                border: none;
            }
        </style>
        <!-- ▲▲▲▲▲▲▲ 表のソートをするために要る ▲▲▲▲▲▲▲ -->
    function historyListDivisionHeader(){
        var historyListViewBlock = document.getElementById('historyBlock');
        document.getElementById('historyBlock').innerHTML = '';

        var divTag = document.createElement('div');
        var historyCountID ='historyCount';
        divTag.setAttribute('id', historyCountID);

        historyListViewBlock.appendChild(divTag);

        var divTag = document.createElement('div');
        var historyScrollID ='historyScroll';
        divTag.setAttribute('id', historyScrollID);
        divTag.setAttribute('style', 'height: 300px; overflow-y: scroll;'); 
        historyListViewBlock.appendChild(divTag);

    //    var historyScrollBlock = document.getElementById(historyScrollID);
    //    var tableTag = document.createElement('table');
        var tableTagID ='historyListView-table';
    //    tableTag.setAttribute('id', tableTagID);
    //    tableTag.setAttribute('class', 'sort-table');
    //    tableTag.setAttribute('data-sortlist', '[[3,0]]');
    //    tableTag.setAttribute('border', '1');
    //    tableTag.setAttribute('style', 'width: 100%; font-size: 90%;');
    //    historyScrollBlock.appendChild(tableTag);
    //    document.getElementById(historyScrollID).innerHTML = '<table id="' + tableTagID + '"' + 
        document.getElementById(historyScrollID).innerHTML = '<table id="historyListView-table"' + 
            ' class="sort-table" data-sortlist="[[3,0]]"' + 
            ' border="1" style="width: 100%; font-size: 90%;"></table>';

        var tableTagBlock = document.getElementById(tableTagID);
        var theadTag = document.createElement('thead');
        var theadTagID ='historyListView-thead';
        theadTag.setAttribute('id', theadTagID);
        tableTagBlock.appendChild(theadTag);

        var theadTagBlock = document.getElementById(theadTagID);
        var trTag = document.createElement('tr');
        var trTagID ='historyListView-tr-midashi'
        trTag.setAttribute('id', trTagID);
        theadTagBlock.appendChild(trTag);

        var trTagBlock = document.getElementById(trTagID);
        var thTag = document.createElement('th');
        thTag.innerHTML = 'ツイート期間';
        trTagBlock.appendChild(thTag);

        var trTagBlock = document.getElementById(trTagID);
        var thTag = document.createElement('th');
        thTag.innerHTML = 'ツイート件数';
        trTagBlock.appendChild(thTag);

        var trTagBlock = document.getElementById(trTagID);
        var thTag = document.createElement('th');
        thTag.innerHTML = 'status';
        trTagBlock.appendChild(thTag);

        var trTagBlock = document.getElementById(trTagID);
        var thTag = document.createElement('th');

        thTag.innerHTML = '読み込み開始日時';
        trTagBlock.appendChild(thTag);

        var trTagBlock = document.getElementById(trTagID);
        var thTag = document.createElement('th');
        thTag.innerHTML = '使用時間';
        trTagBlock.appendChild(thTag);

        var tableTagBlock = document.getElementById(tableTagID);
        var tbodyTag = document.createElement('tbody');
        var tbodyTagID ='historyListView-tbody'
        tbodyTag.setAttribute('id', tbodyTagID);
        tableTagBlock.appendChild(tbodyTag);
    }

    function historyListDivision(){                             //読み込み履歴を作成・表示する
        twitterID = document.getElementById('twitterIDItem').value              //グローバル変数にしている/対象のTwitter ID

        var historyCount = 0;
        for(let i = 0; i < localStorage.length; i++){
            var lskey = localStorage.key(i);
            let result = lskey.indexOf(prefixHistoryMainData + twitterID);
            if(result >= 0){
                if(historyCount == 0){
                    historyListDivisionHeader();
                }

                var timestampSpanSerial = lskey.replace(prefixHistoryMainData + twitterID + '.', '');
                var timestampSpan = timestampSpanSerial.substr( 0, timestampSpanSerial.lastIndexOf('.'));
                var serial = timestampSpanSerial.replace(timestampSpan + '.', '');

                var lsStatusKey = prefixHistoryStatus + twitterID + '.' + timestampSpan + '.' + String(serial);
                var lsStatus = localStorage.getItem(lsStatusKey);                     //locaStorageから取得
                var lsStatusObj = JSON.parse(lsStatus);

                var tbodyBlock = document.getElementById('historyListView-tbody');

                var trTag = document.createElement('tr');
                var trTagID ='historyListView-tr-' + String(historyCount);
                trTag.setAttribute('id', trTagID);
                tbodyBlock.appendChild(trTag);

                var trTagBlock = document.getElementById(trTagID);
                var tdTag = document.createElement('td');
                tdTag.innerHTML = timestampSpan;
                trTagBlock.appendChild(tdTag);

                var tdTag = document.createElement('td');
                tdTag.setAttribute('style', 'padding-right: 1em; text-align: right;');
                tdTag.innerHTML = Number(lsStatusObj.tweetCount);
                trTagBlock.appendChild(tdTag);

                var tdTag = document.createElement('td');
                tdTag.setAttribute('style', 'text-align: center;');
                tdTag.innerHTML = lsStatusObj.status;
                trTagBlock.appendChild(tdTag);

                var tdTag = document.createElement('td');
                tdTag.innerHTML = lsStatusObj.startDatetime;
                trTagBlock.appendChild(tdTag);

                var tdTag = document.createElement('td');
                tdTag.innerHTML = lsStatusObj.timeRequired;
                trTagBlock.appendChild(tdTag);

                historyCount++;
                document.getElementById('historyCount').innerHTML = historyCount + '件ありました。'
            }
        }
    }
//省略
            historyListDivision();     //他の関数内から呼んでいる
//省略
            $(function(){                                       //表のソートをするために要る
                $('.sort-table').tablesorter({
                    textExtraction: function(node){
                        var attr = $(node).attr('data-value');
                        if(typeof attr !== 'undefined' && attr !== false){
                            return attr;
                        }
                        return $(node).text();
                    }
                });
            });

試したこと

最初は、コメントアウトしているようにcreateElementでやってみたところ、動かないので、innerHTMLにしてみましたが同じく動きません。
同じページ内に作ったサンプルコードは正常に動きます。

        <table class="sort-table" data-sortlist="[[3,1]]">
            <thead>
                <tr>
                    <th>番号</th>
                    <th>名前</th>
                    <th>生年月日</th>
                    <th>成績</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>田中太郎</td>
                    <td>8月12日</td>
                    <td>95点</td>
                </tr>
<!-- 省略 -->
                <tr>
                    <td>5</td>
                    <td>東川夏葉</td>
                    <td>1月4日</td>
                    <td>80点</td>
                </tr>
            </tbody>
        </table>


JavaScriptで作成したtableでは使えないのでしょうか?
あるいは、どこか間違っているのでしょうか?
教えて下さい。

補足情報(FW/ツールのバージョンなど)

エディター:Brackets リリース 1.14 ビルド 1.14.2-17770
ブラウザ:Google Chrome バージョン: 93.0.4577.63(Official Build) (x86_64)
OS:macOS Mojave 10.14.6

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kei344

    2021/09/15 16:43

    プラグイン/ライブラリは公式配布サイトのURLを質問文に追記ください。(URLにはリンクを張ることができます)

    キャンセル

  • Lhankor_Mhy

    2021/09/15 16:43

    historyListDivision を呼んでいる部分をご提示ください。

    キャンセル

  • Lhankor_Mhy

    2021/09/15 17:17 編集

    質問の編集を拝読。

    どこから呼ばれているのか知りたかったのですが……
    どうやら、tablesorterとは関係なく呼ばれているようなので、実行順の問題ではないでしょうか?

    キャンセル

  • One_of_Arthur

    2021/09/16 16:38

    「実行順の問題」がヒントになりました。
    ありがとうございました!

    キャンセル

回答 2

check解決した方法

0

アドバイスありがとうございました。
前提の「tablesorter」を使う方法で自己解決しました。

            $(function(){                                       //表のソートをするために要る
                $('.sort-table').tablesorter({
                    textExtraction: function(node){
                        var attr = $(node).attr('data-value');
                        if(typeof attr !== 'undefined' && attr !== false){
                            return attr;
                        }
                        return $(node).text();
                    }
                });
            });


の部分をhistoryListDivision関数内の最後にも記述した所、意図通りに動くようになりました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

<script>
window.addEventListener('DOMContentLoaded', ()=>{
  document.querySelectorAll('.sort-table th').forEach(x=>{
    x.addEventListener('click',()=>{
      const idx=[...x.parentNode.children].indexOf(x);
      const tbody=x.closest('table').querySelector('tbody');
      [...tbody.querySelectorAll('tr')].sort((x,y)=>{
        const tx=x.querySelector(`td:nth-child(${idx+1})`).textContent;
        const ty=y.querySelector(`td:nth-child(${idx+1})`).textContent;
        return tx==ty?0:(tx>ty?1:-1);
      }).forEach(x=>tbody.appendChild(x));
    });
  });
});
</script>
<table class="sort-table">
<thead>
<tr>
<th>番号</th>
<th>名前</th>
<th>生年月日</th>
<th>成績</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>田中太郎</td><td> 8月12日</td><td> 95点</td></tr>
<tr><td>2</td><td>鈴木一郎</td><td> 3月 3日</td><td>100点</td></tr>
<tr><td>3</td><td>佐藤二朗</td><td>12月12日</td><td> 60点</td></tr>
<tr><td>4</td><td>吉田三郎</td><td> 6月 6日</td><td> 75点</td></tr>
<tr><td>5</td><td>東川夏葉</td><td> 1月 4日</td><td> 80点</td></tr>
</tbody>
</table>

昇順/降順切り替え

<style>
.asc:after{
  font-size:0.7em;
content:"▲";
}
.desc:after{
  font-size:0.7em;
content:"▼";
}
</style>
<script>
window.addEventListener('DOMContentLoaded', ()=>{
  document.querySelector('.sort-table th:first-child').classList.add('asc');
  document.querySelectorAll('.sort-table th').forEach(x=>{
    x.addEventListener('click',()=>{
      let y=document.querySelector('.sort-table th.asc,.sort-table th.desc');
      if(x!==y) y?.classList.remove('asc','desc');
      x.classList.toggle('desc',x.classList.contains('asc'));
      x.classList.toggle('asc');
      const idx=[...x.parentNode.children].indexOf(x);
      const tbody=x.closest('table').querySelector('tbody');
      [...tbody.querySelectorAll('tr')].sort((y,z)=>{
        const ty=y.querySelector(`td:nth-child(${idx+1})`).textContent;
        const tz=z.querySelector(`td:nth-child(${idx+1})`).textContent;
        return (ty==tz?0:(ty>tz?1:-1))*(x.classList.contains('asc')?1:-1);
      }).forEach(x=>tbody.appendChild(x));
    });
  });
});
</script>
<table class="sort-table">
<thead>
<tr>
<th>番号</th>
<th>名前</th>
<th>生年月日</th>
<th>成績</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>田中太郎</td><td> 8月12日</td><td> 95点</td></tr>
<tr><td>2</td><td>鈴木一郎</td><td> 3月 3日</td><td>100点</td></tr>
<tr><td>3</td><td>佐藤二朗</td><td>12月12日</td><td> 75点</td></tr>
<tr><td>4</td><td>吉田三郎</td><td> 6月 6日</td><td> 60点</td></tr>
<tr><td>5</td><td>東川夏葉</td><td> 1月 4日</td><td> 80点</td></tr>
</tbody>
</table>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る