Javascript

Table - td index 설정

MuGrammer 2020. 9. 22. 20:28

 

간혹 html table에서 특정 열을 선택하고 싶을때가 있다. 

 

보통은 nth-child(n) 선택자를 쓴다거나 tr을 for문, filter를 사용하여 td의 index() 값이 일치하는 항목을 선택하는 방식으로 기능을 구현할 수 있다. 

 

하지만 이는 colspan, rowspan이 적용된 cell에 대해선 원하는 index가 선택되지 않게 된다. 

 

HTMLTableCellElement의 cellIndex 값은 cell을 감싸고있는 tr 내에서의 index값을 지정하기 때문이다. 

 

<tr>
	<td>0</td> 				=> cellIndex : 0, 원하는 index값 : 0
	<td colspan="2">1</td> 	=> cellIndex : 1, 원하는 index값 : 1
	<td>3</td> 				=> cellIndex : 2, 원하는 index값 : 3
	<td>4</td> 				=> cellIndex : 3, 원하는 index값 : 4
</tr>
<tr>
	<td>0</td> 				=> cellIndex : 0, 원하는 index값 : 0
	<td>1</td> 				=> cellIndex : 1, 원하는 index값 : 1
	<td>2</td> 				=> cellIndex : 2, 원하는 index값 : 2
	<td>3</td> 				=> cellIndex : 3, 원하는 index값 : 3
	<td>4</td> 				=> cellIndex : 4, 원하는 index값 : 4
</tr>

위 코드의 첫 tr의 3번째 td는 cellInex값은 2이지만 실제 화면상으로는 3번째 열에 해당한다. 

 

화면상 열을 기준으로 nth-child(3)을 하였을 경우엔 <td>4</td>와 <td>3</td>이 선택되어진다. 

 

선택하고자하는 항목은 <td>3</td>들이지만 원치않은 항목을 선택하게 되어진다. 

 

해결책

colspan, rowspan을 고려하여 각 td마다 화면상에 보여지는 index값을 지정하도록 한다.

 

이를 위해 index 정보를 담은 2차원 매트릭스를 만든 다음 colspan, rowspan이 적용된 cell들을 지워나가며 알맞은 index를 설정할 수 있도록 한다. 

 

아래의 코드는 jQuery 기반으로 작성되었으며 추후 jQuery를 걷어낸 순수 자바스크립트로 구현할 예정이다. 

 

function setIndex(tableObj, callback) {

  // header는 없을 수도 있기 때문에 tbody의 첫행을 기준으로 한다.
  var columnLength = $('tbody tr:first-child td', $(tableObj)).map(function() {
    return parseInt($(this).attr('colspan') || 1);
  }).get().reduce(function(acc, cur) {
    return acc + cur;
  });

  var rowLength = $('tr', $(tableObj)).length;

  /*
  테이블의 index를 표현하는 2차원 행렬(rowCount * colCount) 생성
  rowspan, colspan에 따라 행렬의 값을 변경
	ex)	5 * 5
		0 1 2 3 4 -> 1행에 지정될 data-col-idx값
		0 1 2 3 4
		0 1 2 3 4
		0 1 2 3 4
  		
		1) 1행의 1열이 rowspan = 3 && colspan = 4일 경우 변경 후 행렬값
  		
		0 X X X 4
		X 1 2 3 4
		X 1 2 3 4
		0 1 2 3 4
  		
  		2) 2행의 3열이 rowspan = 2 && colspan = 2 일 경우 변경 후 행렬값
  		
		0 X X X 4
		X 1 X X 4
		X 1 X X 4
		0 1 2 3 4
  		
  */
  var cellMatrix = new Array();

  for (var i = 0; i < rowLength; i++) {

    var curRowArr = new Array();

    for (var j = 0; j < columnLength; j++) {

      curRowArr.push(j); // data-col-idx로 설정된 index 값을 지정한다. 
    }

    cellMatrix.push(curRowArr);
  }
  
  var curRowIndex = 0;


  // row별 처리
  $('tr', $(tableObj)).each(function(rowIdx, rowObj) {

    var curRowCellObjs = $('td, th', $(this));

    // 현재 row에 해당하는 index array를 가져온다. 
    // curRowCellObjs.length와 일치시키기 위해 지워진 값은 제외한다. 
    var curRowArr = cellMatrix[rowIdx].map(function(el, idx) {

      return {
        colIdx: idx,
        value: el
      }

    }).filter(function(el, idx) {
      return el.value != undefined;
    });

    var accColspan = 0; // colspan을 처리하기 위한 누적 값

    $(curRowCellObjs).each(function(colIdx, colObj) {

      // 이전 cell의 colspan값을 가져와 현재 index 값에 추가한다.
      accColspan += (parseInt($(this).prev().attr('colspan') || 1) - 1);

      // 현재 cell의 rowspan
      var curRowSpan = parseInt($(this).attr('rowspan') || 1);
      // 현재 cell의 colspan
      var curColSpan = parseInt($(this).attr('colspan') || 1);

      // colIdx는 td의 cellIndex값과 동일함. 
      var curColIdx = colIdx + accColspan;

      // colspan, rowspan값에 따라 cellMatrix의 값을 변경한다. 
      for (var i = rowIdx; i < rowIdx + curRowSpan; i++) {

        for (var j = curColIdx; j < curColIdx + curColSpan; j++) {

          if (!(i == rowIdx && j == curColIdx)) {
            cellMatrix[i][curRowArr[j].colIdx] = undefined;
          }
        }
      }

      // data-* 명은 원하는 명칭으로 변경
      $(this).attr('data-col-idx', curRowArr[curColIdx].value);

    });

  });
  
  if(typeof callback === 'function'){
  	callback();
  }

}

 

소스 : jsfiddle.net/mugrammer/dw2z7xk8/

 

Set table cell index & Fixed column - JSFiddle - Code Playground

 

jsfiddle.net

 

사용법은 $('td[data-col-idx=4]') 이렇게 원하는 index 를 지정하여 선택할 수 있다. 

 

 

반응형

'Javascript' 카테고리의 다른 글

Image Lazy Loading  (0) 2019.10.04
Array.sort  (0) 2019.05.08
Eclipse - Emmet (Zen Coding) Plugin 추가  (1) 2018.07.23
[Jquery] click 이벤트 활성화, 비활성화  (1) 2015.03.05
동적테이블 생성  (0) 2015.01.20