때는 2024년 여름 어느 날, ASP.NET 와 관련 UI 라이브러리를 써서 개발 중이던 개발자 1.
해당 UI 라이브러리를 사용해서 edit 가능한 테이블을 만들고 있었는데 문제 발생 🚨
안그래도 회사에서 산 버전은 오래되어서 레퍼런스가 잘 없는데, 고치자고 API 문서를 뒤져보자니 시간 낭비만 하는 것 같아서 그냥 HTML로 만들기로 했다. (ㅠㅠ)
* 구현한 기능
1) table row 추가 및 시퀀스 자동 계산
2) table row 삭제
3) 합계 계산
4) number 컬럼 숫자 체크
5) table data 저장
6) confirm = "Y" 시 readonly
- 데이터 뿌리는 건 C# 으로 구현해서 따로 js 코드에 넣진 않음
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<style>
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.non-clickable {
pointer-events: none;
}
</style>
<script defer>
window.onload = () => {
const arrInput = document.getElementsByTagName("input");
const arrTextarea = document.getElementsByTagName("textarea");
const confirm =
document.getElementById("confirm").value === "Y" ? true : false;
// readonly
if (confirm) {
[...arrInput].forEach((input, index) => {
input.classList.add("non-clickable");
});
[...arrTextarea].forEach((textarea, index) => {
textarea.classList.add("non-clickable");
});
}
};
function isValidNumber(args, event) {
const value = event.target.value;
let bInteger = /^-?\d+$/.test(value) && value <= 100 && value > 0;
if (!bInteger) {
event.target.value = "";
event.target.focus();
}
return bInteger;
}
function sum(args, event) {
const elements = document.getElementsByClassName("ratio");
let sum = 0;
if (!isValidNumber(args, event)) {
return false;
}
for (let element of elements) {
const val = parseInt(element.value);
if (!isNaN(val)) {
sum += val;
}
}
document.getElementsByClassName("footerSum")[0].innerText = sum + "%";
}
function deleteRow(args, event) {
const table = document
.getElementById("table")
.getElementsByTagName("tbody")[0];
const cnt = table.rows.length;
const row = args.closest("tr");
event.preventDefault();
if (cnt <= 1) {
alert("삭제하실 수 없습니다.");
} else {
row.remove();
}
}
function addRow(args, event) {
const table = document
.getElementById("table")
.getElementsByTagName("tbody")[0];
const newRow = table.insertRow();
const confirm =
document.getElementById("confirm").value === "Y" ? true : false;
let cnt = !confirm ? 4 : 3;
const arrSeq = [...document.getElementsByClassName("seq")].map(
(row) => row.value
);
const rownum =
Math.max.apply(Math, arrSeq.length === 0 ? ["0"] : arrSeq) + 1 || 1;
let focusCell = null;
for (let i = 0; i < cnt; i++) {
const cell = newRow.insertCell(i);
if (i === 0) {
// UPJSEQ
cell.innerHTML =
'<input class="seq" type="number" value="' +
rownum +
'" onblur="isValidNumber(this, event);" />';
} else if (i === 1) {
// UAHEAD
cell.innerHTML =
'<textarea class="text" rows="3" maxlength="180"></textarea>';
focusCell = cell;
} else if (i === 2) {
cell.innerHTML =
'<input class="ratio" type="number" onblur="sum(this, event);" />';
} else if (i === 3 && !confirm) {
// delete button
cell.innerHTML =
'<button onclick="deleteRow(this, event);">삭제</button>';
}
}
focusCell?.children[0]?.focus();
return false;
}
async function saveTable(args, event) {
const seq = document.getElementsByClassName("seq");
const text = document.getElementsByClassName("text");
const ratio = document.getElementsByClassName("ratio");
let arrData = [];
let bError = false;
let msg = "";
event.preventDefault();
if (seq.length < 1) {
bError = true;
msg = "처리할 데이터가 없습니다.";
}
if (bError) {
alert(msg);
return false;
}
for (let i = 0; i < seq.length; i++) {
arrData.push({
seq: seq[i].value,
text: text[i].value,
ratio: ratio[i].value,
});
}
let data = JSON.stringify(arrData);
console.log(data);
try {
const response = await fetch("../etc/submit.js", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: data,
});
if (!response.ok) {
throw new Error("Network error : "); // 500 error
}
const jsonResult = await response.json();
const result = JSON.parse(jsonResult.d); // asp
if (result.error) {
alert(result.message);
} else {
alert("saved.");
}
} catch (error) {
console.error("Fetch error : ", error);
}
}
</script>
<button id="save" onclick="saveTable(this, event);">SAVE</button>
<button id="add" onclick="return addRow(this, event);">ADD</button>
<input type="hidden" id="confirm" />
<table border="1" id="table">
<thead>
<tr>
<th style="width: 20%">SEQ</th>
<th style="width: 40%">TEXT</th>
<th style="width: 20%">RATIO</th>
<th style="width: 20%">DEL</th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<th colspan="2">SUM</th>
<td class="footerSum"></td>
<td></td>
</tfoot>
</table>
</body>
</html>
SEQ | TEXT | RATIO | DEL | SUM |
---|
'JavaScript' 카테고리의 다른 글
Deep Dive : 고차 함수 관련 JS 추가 개념 (0) | 2024.07.20 |
---|---|
배열 / 유사 배열(Array-like objects) 비교 + Prototype (0) | 2024.07.09 |
Document. getElementById / getElementsByName / querySelector (0) | 2024.07.03 |
240608 리액트 스터디 : <script> async, defer (0) | 2024.06.12 |
240525 리액트 스터디 : DOM, Text, in / hasOwnProperty (0) | 2024.06.12 |