เทคนิคการเลื่อนสลับแถว (Drag & Drop) ใน Table ด้วย JavaScript

บล็อกนี้น่าจะเป็น EP สุดท้ายของซีรี่ส์ Drag & Drop row ใน HTML Table แล้ว จากบล็อกที่ผ่านๆ มา ผู้เขียนได้ใช้เทคนิคต่างๆ โดยพึ่งพา framework ที่ใช้ในการพัฒนาโปรแกรม เช่น ASP.NET, Blazor หรือ jQuery แต่สำหรับบล็อกนี้เราจะเขียนโดยใช้ JavaScript ล้วนๆ บวกกับ CSS จาก Bootstrap อีกนิดหน่อยเพื่อความสวยงามของ Table และเพื่อไม่ให้เป็นการเสียเวลา เรามาลุยกันเลยครับ

1. เริ่มต้นด้วยการเตรียมไฟล์ HTML ดังโค้ดด้านล่าง

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
		<title>Drag & Drop Table Row</title>
		
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
	</head>
	<body style="padding:10px">
		
		<table style="width:90%;" class="table table-striped">
			<thead>
				<tr >
					<th>ลำดับ</th>
					<th>จังหวัด</th>
				</tr>
			</thead>
			<tbody id="provinceList">
			</tbody>
		</table>
		
	</body>
</html>

2. เพิ่ม code JavaScript สำหรับเพิ่มข้อมูลลงใน Table ใน event window.onload โดยเราจะเพิ่มแท็ก <tr> ใน element tbody ที่มี id=”provinceList” และระบุ class=”prv-item” สำหรับใช้ในการอ้างถึงจากโค้ด JavaScript

<script>

window.onload = async () => {

	const provinces = ['สงขลา','ปัตตานี','ยะลา','นราธิวาส','สตูล'];
	for (let i = 0; i < provinces.length; i++) {
		provinceList.innerHTML += "<tr class='prv-item' data-value=" + i + "><td> " + (i + 1) + "</td><td>" + provinces[i] + "</td></tr>";
	};

};

</script>

ซึ่งจะได้ผลลัพธ์หน้าจอดังรูป และเป้าหมายของเราก็คือสามารถคลิกเลือกจังหวัด จากนั้นลากและวางไปยังตำแหน่งที่ต้องการได้

3. และเพิ่มโค้ด JavaScript สำหรับผูก event ต่างๆ เข้ากับแต่ละ <tr> ที่เพิ่มเข้าไป ใน event window.onload เพื่อให้สามารถลากและวางได้

let listPrvItems = document.querySelectorAll(".prv-item");
listPrvItems.forEach((element) => {
	element.draggable = true;
	element.addEventListener("dragstart", dragStart, false);
	element.addEventListener("dragover", dragOver, false);
	element.addEventListener("drop", drop, false);
});

4. เพิ่มโค้ด JavaScript ส่วนควบคุม event ต่างๆ คือ เมื่อเริ่มกดลาก เมื่อกดวาง และฟังก์ชันสำหรับหาตำแหน่งของแถว (<tr>) ที่เริ่มกดลาก ดังนี้

//หาลำดับของ tr จาก value ที่ส่งมา ทำการวนลูปเทียบกับ data-value ใน tr ของตารางทั้งหมด
const getPosition = (value) => {
	let elementIndex;
	let listPrvItems = document.querySelectorAll(".prv-item");
	listPrvItems.forEach((element, index) => {
		let elementValue = element.getAttribute("data-value");
		if (value == elementValue) {
			elementIndex = index;
		}
		});
	return elementIndex;
};

//เก็บตำแหน่ง x,y และ element ที่เริ่มคลิกลาก
function dragStart(e) {
	initialX = e.clientX;
	initialY = e.clientY;
	//Set current Element
	currentElement = e.target;
}

function dragOver(e) {
	e.preventDefault();
}

//เหตุการณ์วาง
const drop = (e) => {
	e.preventDefault();

    // เก็บตำแหน่ง x, y ที่วาง
	let newX = e.clientX;
	let newY = e.clientY;

	//Set targetElement(where we drop the picked element).It is based on mouse position
    // เก็บ element ที่จะถูกวางแทนที่
	let targetElement = document.elementFromPoint(newX, newY);

    // ตรวจสอบว่า element ที่ถูกวาง เป็น TD หรือไม่ ถ้าใช่ จะเปลี่ยนให้เป็น TR ที่เป็น parent ของ TD นั้น
    // เนื่องจากการลากวาง จะเป็นการลากวางและแทนที่ทั้งแถว ซึ่งก็คือ TR
	if(targetElement.nodeName == "TD")
	{
		targetElement = targetElement.parentNode;
	}

    // เก็บ value จาก element ต้นทางและปลายทาง
	let currentValue = currentElement.getAttribute("data-value");
	let targetValue = targetElement.getAttribute("data-value");

	//หาตำแหน่ง TR จาก value
	let [currentPosition, targetPosition] = [
		getPosition(currentValue),
		getPosition(targetValue),
	];
	initialX = newX;
	initialY = newY;

	try {

	if (currentPosition < targetPosition) {
      
      // ถ้าแถวที่เริ่มลาก น้อยกว่าแถวที่จะวาง จะทำการแทรกในตำแหน่งด้านล่างของแถวที่จะวาง
	  targetElement.insertAdjacentElement("afterend", currentElement);
	} else {

      // ถ้าแถวที่เริ่มลาก มากกว่าแถวที่จะวาง จะทำการแทรกในตำแหน่งด้านบนของแถวที่จะวาง
	  targetElement.insertAdjacentElement("beforebegin", currentElement);
	}
	} catch (err) {}
}; 

4. เมื่อทดสอบการทำงาน รายชื่อจังหวัดในตารางจะสามารถคลิก ลาก และวางไปยังตำแหน่งที่ต้องการได้

5. และเมื่อ drop ลงไปยังตำแหน่งที่ต้องการ จังหวัดที่ลากมาก็จะแทรกเข้าไปยังตำแหน่งที่ drop

จากซีรี่ส์ Drag & Drop Row ใน Table อันยาวนานนี้ ผู้เขียนหวังเป็นอย่างยิ่งว่าจะมีประโยชน์กับผู้อ่านไม่มากก็น้อยที่จะนำไปประยุกต์ใช้กับงานของตัวเอง แล้วเจอกันใหม่โอกาสหน้า เมื่อผู้เขียนจะมีเหตุให้ต้องเข้ามาอีก สวัสดีครับ


แหล่งข้อมูลอ้างอิง