ปัญหาที่คุณพบเกิดจาก การแปลงชนิดข้อมูลที่ไม่ถูกต้อง (Type Coercion) ระหว่างการโหลดข้อมูลจาก Local Storage เข้าสู่ฟังก์ชัน addRow ซึ่งทำให้ค่าที่เป็น Boolean (true / false) ถูกแปลงเป็น String ('true' / 'false') โดยไม่ได้ตั้งใจ
ส่วนประเด็นเรื่องตัวอักษร P (ตัวใหญ่) กับ p (ตัวเล็ก) นั้น ไม่มีผลต่อโค้ด JavaScript ที่ใช้ในการบันทึกและแสดงผล เพราะโค้ดทั้งหมดใช้คีย์เป็น paid (ตัวเล็ก) ตรงกัน แต่มีผลต่อการอ่านค่าจาก Local Storage เมื่อมีการแปลงชนิดข้อมูลผิดพลาดครับ
การแก้ไข: 2 จุดในโค้ด JavaScript
คุณต้องแก้ไขในฟังก์ชัน addRow และ duplicateRow เพื่อให้แน่ใจว่าค่าสำหรับ paid และ pay ถูกเก็บเป็น Boolean เสมอ:
1. แก้ไขในฟังก์ชัน addRow (แก้ปัญหาหลัก: การโหลดจาก Local Storage)
ในฟังก์ชัน addRow ให้เปลี่ยนวิธีการกำหนดค่า paid และ pay จากการแปลงเป็น String ให้เป็นการบังคับให้เป็น Boolean (!!)
ค้นหาส่วนนี้ในฟังก์ชัน addRow:
JavaScript
// โค้ดเดิม (ทำให้ boolean กลายเป็น string เช่น 'false')
const rowData = {
// ...
premium: String(d.premium || ''),
paid: String(d.paid || ''), // ❌ บรรทัดนี้ทำให้เกิดปัญหา
pay: String(d.pay || ''), // ❌ บรรทัดนี้ทำให้เกิดปัญหา
note: d.note || '',
// ...
};
แก้ไขเป็น:
JavaScript
// โค้ดที่แก้ไข (บังคับให้เป็น boolean: true หรือ false)
const rowData = {
// ...
premium: String(d.premium || ''),
paid: !!d.paid, // ✅ ใช้ !! เพื่อให้แน่ใจว่าเป็น Boolean
pay: !!d.pay, // ✅ ใช้ !! เพื่อให้แน่ใจว่าเป็น Boolean
note: d.note || '',
// ...
};
2. แก้ไขในฟังก์ชัน duplicateRow (แก้ปัญหาเสริม: การคัดลอกแถว)
เมื่อคุณกดปุ่ม Duplicate (คัดลอก) ฟังก์ชันนี้จะดึงค่าจาก Input Element มาใช้ ซึ่งสำหรับ Checkbox คุณต้องดึงค่า .checked ไม่ใช่ .value
ค้นหาส่วนนี้ในฟังก์ชัน duplicateRow:
JavaScript
// โค้ดเดิม (อ่านค่า .value ซึ่งเป็น string 'on' หรือ '')
const d={
// ...
premium:cells[4].value,
paid:cells[5].value, // ❌ ต้องเป็น .checked
pay:cells[6].value, // ❌ ต้องเป็น .checked
note:cells[7].value,
// ...
};
แก้ไขเป็น:
JavaScript
// โค้ดที่แก้ไข (อ่านค่า .checked ซึ่งเป็น boolean true หรือ false)
const d={
// ...
premium:cells[4].value,
paid:cells[5].checked, // ✅ ใช้ .checked
pay:cells[6].checked, // ✅ ใช้ .checked
note:cells[7].value,
// ...
};
เมื่อแก้ไขทั้งสองจุดแล้ว ระบบจะสามารถโหลดค่าสถานะ paid ที่เป็น Boolean จาก Local Storage ได้อย่างถูกต้อง และแสดงผลเป็น Checkbox ที่ถูกติ๊ก/ไม่ถูกติ๊ก ตามค่าที่บันทึกไว้ครับ
เดิมที โค๊ดทำงานได้เพราะ
// ใน addRow
paid: String(d.paid || ''),
pay: String(d.pay || ''),
// ใน duplicateRow
paid:cells[5].value, // ❌ โค้ดเดิม
pay:cells[6].value, // ❌ โค้ดเดิมตามหลักต้องทำแบบนี้
// ใน addRow
paid: !!d.paid, // บังคับให้เป็น true/false ก่อนบันทึก
pay: !!d.pay,
// ใน duplicateRow
paid: cells[5].checked, // อ่านค่าเป็น Boolean
pay: cells[6].checked, // อ่านค่าเป็น Booleanคำอธิบาย ละเอียด
เมื่อ Input type เป็น Checkbox การเรียกใช้
.valueจะไม่คืนค่าสถานะว่าถูกติ๊กหรือไม่ แต่จะคืนค่าเป็น String ตามคุณสมบัติvalueของ Input นั้นแทนครับ ซึ่งโดยทั่วไปแล้ว:
- ถ้า Checkbox ถูกติ๊ก (
.checked = true):.valueจะคืนค่าเป็น"on"(String) หรือค่าใดก็ตามที่คุณกำหนดไว้ในแอตทริบิวต์valueของ HTML- ถ้า Checkbox ไม่ถูกติ๊ก (
.checked = false):.valueจะคืนค่าเป็น""(Empty String) หรือค่าใดก็ตามที่คุณกำหนดไว้ดังนั้น ในโค้ด
duplicateRowที่มีอยู่เดิม:JavaScript
paid:cells[5].value, // ❌ โค้ดเดิม pay:cells[6].value, // ❌ โค้ดเดิมผลกระทบของการใช้
.valueกับ Checkbox
- สำหรับ Checkbox ที่ถูกติ๊ก: จะได้ค่าเป็น String
"on"(หรือค่าอื่นที่ไม่ใช่ Empty String)
- เมื่อนำไปใช้ในบริบทของ Boolean (เช่น ใน
addRow) ค่า"on"จะถูกแปลงเป็นtrue(Boolean)- ผลลัพธ์: ถูกต้อง
- สำหรับ Checkbox ที่ไม่ถูกติ๊ก: จะได้ค่าเป็น Empty String
""
- เมื่อนำไปใช้ในบริบทของ Boolean (เช่น ใน
addRow) ค่า""(Empty String) จะถูกแปลงเป็นfalse(Boolean)- ผลลัพธ์: ถูกต้อง
สรุป
ถึงแม้ว่าการใช้
.valueจะให้ผลลัพธ์trueหรือfalseทางตรรกะที่ถูกต้องอยู่แล้ว เนื่องจาก JavaScript มีการ Type Coercion (การแปลงชนิดข้อมูลอัตโนมัติ) แต่ก็เป็นวิธีที่ ไม่ถูกต้องตามหลักการเขียนโปรแกรม และอาจสร้างความสับสนได้ในอนาคตการแก้ไขที่ถูกต้องและชัดเจนตามวัตถุประสงค์ที่สุดคือการใช้
.checkedเสมอ เพราะมันถูกออกแบบมาเพื่อคืนค่าสถานะ Boolean ของ Checkbox โดยตรง:JavaScript
paid:cells[5].checked, // ✅ คืนค่าเป็น true หรือ false ตรงๆ pay:cells[6].checked, // ✅ คืนค่าเป็น true หรือ false ตรงๆคำแนะนำ: แม้ว่าโค้ดเดิมจะบังเอิญทำงานได้ (โดยอาศัย Type Coercion) แต่คุณควรเปลี่ยนไปใช้
.checkedตามที่ผมได้แนะนำไปในคำตอบก่อนหน้า เพื่อให้โค้ดของคุณชัดเจนและเชื่อถือได้มากขึ้นครับ