JavaScriptでテーブルを操作する

テーブルを操作するプロパティやらメソッド。-1がデフォルトで最後の行。

命令 プロパティ メソッド オブジェクト
列の取得 rows   table,thead,tbody,tfoot
セルの取得 cells   tr,th,rows[i]
列の追加   insertRow table,thead,tbody,tfoot
セルの追加   insertCell tr,th,rows[i]
列の削除   deleteRow table,thead,tbody,tfoot
セルの削除   deleteCell tr,th,rows[i]
セルの番号取得 cellIndex   td,cells[i]
テーブル全体での列の番号取得 rowIndex   table
列の番号取得 sectionRowIndex   tr,th,row[i]

cellIndexでは、同じ列のセルは同じ番号が振られる。
0 1 2
0 1 2
columnが列、rowが行という意味らしいが、日本語で考えたら横の行がcolumnで、縦の列がrowですから上手く整理しないとごちゃごちゃになります。

rowIndexとsectionRowIndexは、特定のtrとかの列番号を返すのは同じだけど、テーブル全体から数えて何番目か、そのtrのセクション(thead,tfoot,tbody)タグから数えて何番目かの違い。

テーブル追加・削除サンプルを読み解く

こちらのページで紹介されているスクリプトを考えて見ます。

<table id="sample" border="1">
    <thead id="samplethead">
        <tr>
            <th>名前A</th>
            <th>名前B</th>
            <th>名前C</th>
        </tr>
    </thead>
    <tbody id="sampleTbodyA">
        <tr>
            <td>1行目1列目</td>
            <td>1行目2列目</td>
            <td>1行目3列目</td>
        </tr>
    </tbody>
    <tbody id="sampleTbodyB">
        <tr>
            <td>2行目1列目</td>
            <td>2行目2列目</td>
            <td>2行目3列目</td>
        </tr>
        <tr>
            <td>3行目1列目</td>
            <td>3行目2列目</td>
            <td>3行目3列目</td>
        </tr>
    </tbody>
</table>

このサンプルスクリプトではsrcElementを使用しているので、Firefoxでは動きません。そこで、Firefoxに対応させるためのイベントリスナを先に実行しておきます。

//srcElementをtargetに関連付ける
if (window.addEventListener){ //IE以外に適用(IE8以下はattachEvent)
    window.addEventListener("click",function(e){ //クリックイベントが起こったら
    window.event = e; //発火したイベントはwindow.eventと同じ
    window.event.srcElement = e.target; //firefox用のイベントを起した要素を、非対応のwindow.event.srcElementに対応させる。
},true); //trueはキャプチャーフェーズでIEだけ非対応
}
function sample(){
	var bt = window.event.srcElement;//この場合押されたボタンのinput要素
	if(bt.nodeName != 'INPUT') return;//ボタン以外(inputでなければ)なら抜け出す
	//if(bt.parentNode.cellIndex>0) return;//押されたボタンのinputの親のtd、thのcellが1以上(+ーのボタンでなければ)なら抜け出す
	var tr = bt.parentNode.parentNode;//押されたボタンのinputの親の親すなわちtr
	//var thF = (tr.parentNode.nodeName == 'THEAD');//trの親の要素はthead→題名欄thの親を指定
	var tbod = tr.parentNode;
	//var tbod = (thF)?tr.parentNode.parentNode.tBodies[0]:tr.parentNode;//theadならtbod=tBodies[0]、tbodyならtbod=押されたボタンの属するtbody
	if(bt.value == '削除'){//マイナスボタンなら
		//if(thF)return;
		/*if(tbod.rows.length<1){
		alert("こんなことないけどエラーだよ");
			return;
		}*/
		tbod.deleteRow(tr.sectionRowIndex);//sectionRowIndexはtrのtbodyから数えて何番目か。
	} 
}

変数btに値を代入。もしbt.event.srcElement(クリックイベントが起こったinput要素)のノード名が、inputじゃなかったら、undefinedを返す。function内だからforとかのようなbreakとはちょっと違う。

もしbt.bt.parentNode.cellIndex>1(inputの親であるtdのセル番号が1より大きい=+とーボタンが入ったセル行でない)ならreturn。

変数trにイベントが起こったinputの親(td)の親(tr)を代入。その変数trの親(theadかtbody)のノード名がtheadという比較文自体をthFという変数に代入。

tbodという変数に、P=A?B:C;(PはAが真ならB、偽ならC文)を利用して、theadつまり1行目だったら、tbodはtrの親(thead)の親(table)の最初のtbodyまでを代入、違う(tbodyだった)なら、trの親(tbody)までを代入。

var newt = document.getElementById("sample").tBodies[0];//tbodyがなければtableの最後の行

var newtr = newt.insertRow(-1);//引数:新しい行の行番号( 0 が一行目)index に -1 または行数に等しい場合、行は最後の行として追加される。
var newtd0 = newtr.insertCell(0);
var newtd1 = newtr.insertCell(1);//row、th、trオブジェクトのメソッド
var newtd2 = newtr.insertCell(2);
var newtd3 = newtr.insertCell(3);
var newtd4 = newtr.insertCell(4);
var newtd5 = newtr.insertCell(5);
var newtd6 = newtr.insertCell(6);
var newtd7 = newtr.insertCell(7);
var newtd8 = newtr.insertCell(8);
newtd0.innerHTML = "";
newtd1.innerHTML = "1";
newtd2.innerHTML = "2";
newtd3.innerHTML = "3";
newtd4.innerHTML = "4";
newtd5.innerHTML = "5";
newtd6.innerHTML = "6";
newtd7.innerHTML = "7";
newtd8.innerHTML = "8";
*/

DOMで行を追加するtbodyを選んで、insertRow()で追加する。これを変数にいれるんで、それ以下のinsertCell()は、その追加した行に対して追加される。

以下の様な形にすると、行がその都度追加されてしまって、追加したセルが横一列に並ばない。同じindex番号のセルは縦並びになる。

var newt = document.getElementById("sample").tBodies[0];//tbodyがなければtableの最後の行

newt.insertRow(-1).insertCell(0).innerHTML = "";
newt.insertRow(-1).insertCell(0).innerHTML = "1";
newt.insertRow(-1).insertCell(1).innerHTML = "1";
newt.insertRow(-1).insertCell(2).innerHTML = "2";
newt.insertRow(-1).insertCell(3).innerHTML = "3";
newt.insertRow(-1).insertCell(4).innerHTML = "4";
newt.insertRow(-1).insertCell(5).innerHTML = "5";
newt.insertRow(-1).insertCell(6).innerHTML = "6";
newt.insertRow(-1).insertCell(7).innerHTML = "7";
newt.insertRow(-1).insertCell(8).innerHTML = "8";

テーブルにセル追加、削除のスクリプトはこれでいいと思われる。

function clrow(o){
	var inp = o.getElementsByTagName('input');
	for(var i=0;inp[i];i++){
		if(inp[i].type == 'text') {
			inp[i].value = inp[i].defaultValue;
		}
	}
}

とばして、clrow関数の宣言。inp変数に引数(2行目)のinputを代入。その行のinputは+と-とテキストフィールドの3つある。<

for文にて、inputを1個ずつ探して、typeがtextのものが見つかったら、そのvalueをdefaultvalueにする。最後の1行を削除しようとすると内容(input)のクリアだけ行われるための命令。

if(bt.value == '-'){
		if(thF)return;
		if(tbod.rows.length<2){
			clrow(tbod.rows[0]);
			return;
		}
		tbod.deleteRow(tr.sectionRowIndex);

もし選択されたinputのvalueがマイナスなら、もし親がtheadならundefiend、もしtbodyの行が2よりも小さいなら、clrowが実行されて内容だけがクリアされる。

それ以外なら、tbodyの(押されたinputのtrの行の番号)がdeleterowで行削除される。

} else {
		var rcopy = tbod.rows[0].cloneNode(true);
		clrow(rcopy);
		if(!thF && tr.sectionRowIndex+1==tbod.rows.length) {
			tbod.appendChild(rcopy);
		} else {
			tbod.insertBefore(rcopy,(thF)?tbod.rows[0]:tr.nextSibling);
		}
	}

押されたボタンがマイナスじゃない(+)なら、変数rcopyにtbodyの1行目のノードを複製するしたものを代入。trueだから値もコピーされるため、clrow関数でテキストフィールドを初期化。

もし、クリックされたinputの親がtheadでなく、そのtrの行番号+1番目がtbodyの総列数と同じなら、tbodyの最後部にrcopyを追加する。(最後の行に追加するパターン)

それ以外なら、tbodyの子ノードとして、rcopyを、押したボタンの親がtheadならtbodyの先頭に、押したボタンの親がtbodyならそのtrの次の行(エレメント)へ。

コメントor補足情報orご指摘あればをお願いします。

(件名or本文内でキーワード検索できます)



記事No2393 題名:よろしくお願いいたします 投稿者:家島ダイアグラム 投稿日:2023-02-05 20:01:30

家島の情報サイトです。船やバスの時刻表や天気など様々な情報を発信中!!時刻表が変わった・間違いがある・ご要望の場合は連絡お願いします。Twitter・LINEをフォローまたはRSSでサイト更新時に通知します。
家島ダイアグラム
https://hyogo.ie-t.net/ #家島 #坊勢 #男鹿 #時刻表 #船 #神姫バス


  • << 前のページ
  • 次のページ >>
ページトップへ