HTML, CSS, JavaScript
[JavaScript] 테이블 토글 버튼(트리 구조 테이블)
망고고래
2025. 3. 7. 21:49
1. 개요
- 테이블: api 통신을 통해 받아서 오는 데이터로 작성
- 토글 버튼은 각 행에 설치하되, 컬럼 안에 들어있지 않고 absolute를 사용해 떠있게 함
- 토글 버튼을 클릭한 경우의 동작
각 행의 데이터 중 sub_table_YN의 값이 Y: 해당 행 아래에 서브 테이블을 보여줌
sub_table_YN의 값이 N: 서브 테이블 데이터를 추가하는 모달 오픈
이 동작은 라디오 버튼이 체크된 후에 이루어져야 함
선택(라디오 버튼) | 컬럼1 | 컬럼2 | 컬럼3 | 컬럼4 |
+ ⊙ | ||||
+ ⊙ |
2. 코드
//현재 활성화되어있는 토글 버튼을 관리하기 위한 변수
let activeToggleButton = null;
function updateTable(data){
//테이블과 티바디 초기화
const table = document.getElementById('table');
const tbody = table.querySelector('tbody') || table.createTBody();
tbody.innerHTML = '';
data.forEach((tableData, index) => {
//행 생성 및 데이터셋 초기화
const row = tbody.insertRow();
row.dataset.data1 = tableData.data1 || '';
//...
row.dataset.hasSubData = tableData.sub_data_YN === 'Y' ? 'true' : 'false';
//첫 번째 td 생성, 라디오 버튼과 토글 버튼 추가
const firstTd = document.createElement('td');
firstTd.style.position = 'relative';
//라디오 버튼 추가
const radio = document.createElement('input');
radio.type = 'radio';
radio.name = 'tableRadio';
firstTd.appendChild(radio);
//토글 버튼 추가
//토글 스타일 설정
const toggleButton = document.createElement('button');
toggleButton.className = 'sub-data-toggle'; //스타일 적용을 위한 클래스
if(tableData.sub_data_YN === 'Y'){
toggleButton.classList.add('has-sub-data');
}
toggleButton.textContent = '+';
//클릭 이벤트 설정
toggleButton.onclick = function(e){
e.preventDefault();
e.stopPropagation();
radio.checked = true;
//서브 데이터를 라디오가 선택된 행을 기준으로 가져오기 때문에
//라디오 체크가 필요
//라디오가 클릭된 뒤에 서브 데이터를 불러오도록 지연
setTimeout(() => {
//기존의 활성화된 토글 버튼 초기화
if(activeToggleButton && activeToggleButton !== this){
activeToggleButton.className.remove('active');
activeToggleButton.textContent = '+';
//기존 하위 테이블 제거
const previousRow = activeToggleButton.closest('tr');
if(previousRow){
toggleSubContractVisibility(previousRow);
}
activeToggleButton = null;
}
//기존에는 dataset의 YN으로 체크했으나, 클래스 has-sub-data로 체크
if(this.classList.contains('has-sub-data')){
//현재 버튼이 active 상태인 경우
if(this.classList.contains('active')){
console.log('active 상태에서 클릭');
toggleSubContractVisibility(row); //하위 계약 테이블 제거
this.classList.remove('active'); //active 상태 제거
this.textContent = '+'; //버튼 텍스트 변경
activeToggleButton = null; //활성 버튼 참조 제거
return; //함수 종료
}
console.log('비활성 상태에서 클릭');
this.classList.add('active');
this.textContent = '-';
activeToggleButton = this;
updateSubContractTable(row);
}else{
openSubDataModal('add'); //데이터 신규 작성 모달
}//has-sub-data 클래스 유무 if문
}, 100);
};//토글 버튼 클릭 이벤트 설정
firstTd.appendChild(toggleButton);
row.appendChild(firstTd);
//나머지 내용 HTML로 추가
row.insertAdjacentHTML('beforeend', `
<td class="text-center">${index + 1}</td>
...
`);
//다른 행 클릭시 활성화된 토글 버튼 비활성화
row.addEventListner('click', function(e){
//토글 버튼 클릭은 제외
if(e.target.classList.contains('sub-contract-toggle')){
return;
}
radio.checked = true;
if(activeToggleButton){
activeToggleButton.classList.remove('active');
activeToggleButton.textContent = '+';
const previousRow = activeToggleButton.closest('tr');
if(previousRow){
toggleSubContractVisibility(previousRow);
}
activeToggleButton = null;
}
});
});
}
내부에서 호출하는 다른 함수들
function toggleSubContractVisibility(parentRow){
const nextRow = parentRow.nextElementSibling;
if(nextRow && nextRow.classList.contains('sub-contract-row')){
nextRow.remove();
}
}
3. 리뷰
새로 알게 된 함수
insertAdjacentHTML()
더 공부할 것
1) html 요소 자바스크립트로 조작하기
- classList.add()
- classList.contains()
- appendChild()
- createElement()
- element.name = ' '
- element.type = ' '
- creatTBody()
등등