Now.js Framework Documentation
data-script
data-script
ภาพรวม
data-script ระบุ global function ที่จะเรียกเมื่อ template โหลดและพร้อมใช้งาน ทำให้สามารถ initialize JavaScript สำหรับ template components ได้
ใช้เมื่อ:
- Initialize JavaScript เมื่อ template โหลด
- ตั้งค่า event listeners หรือ third-party libraries
- สร้าง cleanup functions สำหรับ navigation
ทำไมต้องใช้:
- ✅ แยก HTML และ JS ออกจากกันอย่างชัดเจน
- ✅ รับข้อมูลจาก API อัตโนมัติ
- ✅ รองรับ cleanup functions
- ✅ ทำงานร่วมกับ RouterManager
การใช้งานพื้นฐาน
Template กับ Script
profile.html:
<main data-script="initProfile">
<h1 data-text="user.name"></h1>
<form data-form="editProfile">
<input type="text" name="bio" data-attr="value:user.bio">
<button type="submit">บันทึก</button>
</form>
</main>main.js:
function initProfile(element, data) {
console.log('โหลด Profile แล้ว!', element);
console.log('ข้อมูลจาก API:', data);
// Initialize components
const form = element.querySelector('form');
// Return cleanup function (ไม่บังคับ)
return () => {
console.log('Cleanup Profile');
};
}Syntax
<element data-script="functionName">| ส่วน | คำอธิบาย |
|---|---|
functionName |
ชื่อ global function ที่จะเรียก |
Function Signature
function functionName(element, data) {
// element: DOM element ที่มี data-script attribute
// data: ข้อมูลจาก API (ถ้า route มี data-load-api)
// โค้ด initialization
// Return cleanup function (ไม่บังคับ)
return () => {
// โค้ด cleanup ทำงานเมื่อ navigate ออก
};
}Parameters
| Parameter | ประเภท | คำอธิบาย |
|---|---|---|
element |
HTMLElement | DOM element ที่มี data-script |
data |
Object | ข้อมูลจาก API (ถ้าใช้ data-load-api) |
Return Value
| Return | ผลลัพธ์ |
|---|---|
undefined |
ไม่มี cleanup |
Function |
ถูกเรียกเมื่อ template ถูกลบ |
ฟีเจอร์
1. Basic Initialization
<div class="chart-container" data-script="initChart">
<canvas id="myChart"></canvas>
</div>function initChart(element, data) {
const canvas = element.querySelector('#myChart');
const chart = new Chart(canvas, {
type: 'bar',
data: data.chartData
});
return () => {
chart.destroy();
};
}2. กับ API Data
Router config:
routes: {
'/dashboard': {
template: 'dashboard.html',
title: 'Dashboard',
'data-load-api': 'api/dashboard/stats'
}
}dashboard.html:
<main data-script="initDashboard">
<div id="stats"></div>
</main>function initDashboard(element, data) {
// data = { totalUsers: 150, revenue: 50000, ... }
console.log('Stats:', data);
renderStats(element.querySelector('#stats'), data);
}3. หลาย Scripts
<div class="page">
<header data-script="initHeader">
<nav>...</nav>
</header>
<main data-script="initMainContent">
<div class="content">...</div>
</main>
<aside data-script="initSidebar">
<div class="widgets">...</div>
</aside>
</div>Functions ถูกเรียกตามลำดับ DOM (บนลงล่าง)
4. Cleanup Functions
function initTimer(element, data) {
const timerEl = element.querySelector('#timer');
// เริ่ม interval
const intervalId = setInterval(() => {
timerEl.textContent = new Date().toLocaleTimeString();
}, 1000);
// Return cleanup - ถูกเรียกเมื่อ navigate ออก
return () => {
clearInterval(intervalId);
};
}ตัวอย่างขั้นสูง
Interactive Map
<div class="map-page" data-script="initMap">
<div id="map" style="height: 400px;"></div>
<button id="center-btn">กลับตำแหน่งเดิม</button>
</div>function initMap(element, data) {
const mapEl = element.querySelector('#map');
const centerBtn = element.querySelector('#center-btn');
// Initialize Leaflet map
const map = L.map(mapEl).setView([13.7, 100.5], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// เพิ่ม markers จากข้อมูล
data.locations.forEach(loc => {
L.marker([loc.lat, loc.lng])
.addTo(map)
.bindPopup(loc.name);
});
// Event listeners
const handleCenter = () => {
map.setView([13.7, 100.5], 13);
};
centerBtn.addEventListener('click', handleCenter);
// Cleanup
return () => {
centerBtn.removeEventListener('click', handleCenter);
map.remove();
};
}ฟอร์มกับ Validation
<form data-form="register" data-script="initRegisterForm">
<input type="email" name="email" id="email">
<span class="error" id="email-error"></span>
<input type="password" name="password" id="password">
<span class="error" id="password-error"></span>
<button type="submit">สมัครสมาชิก</button>
</form>function initRegisterForm(element, data) {
const emailInput = element.querySelector('#email');
const passwordInput = element.querySelector('#password');
let debounceTimer;
const validateEmail = async () => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(async () => {
const email = emailInput.value;
// Validation logic
}, 500);
};
emailInput.addEventListener('input', validateEmail);
return () => {
clearTimeout(debounceTimer);
emailInput.removeEventListener('input', validateEmail);
};
}Live Chat
function initLiveChat(element, data) {
const messagesEl = element.querySelector('#messages');
const inputEl = element.querySelector('#message-input');
const sendBtn = element.querySelector('#send-btn');
// Connect WebSocket
const ws = new WebSocket('wss://chat.example.com');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
appendMessage(messagesEl, msg);
};
const sendMessage = () => {
const text = inputEl.value.trim();
if (text) {
ws.send(JSON.stringify({ type: 'message', text }));
inputEl.value = '';
}
};
sendBtn.addEventListener('click', sendMessage);
inputEl.addEventListener('keydown', (e) => {
if (e.key === 'Enter') sendMessage();
});
// Cleanup - ปิด WebSocket
return () => {
ws.close();
sendBtn.removeEventListener('click', sendMessage);
};
}API อ้างอิง
เมื่อ Scripts ทำงาน
| Event | พฤติกรรม |
|---|---|
| Template load | Script ถูกเรียกหลัง DOM พร้อม |
| Route navigation | Cleanup ก่อนหน้าถูกเรียก, script ใหม่ถูกเรียก |
| Manual cleanup | เรียก RouterManager.cleanup() |
ลำดับการทำงาน
- Template HTML ถูก render
data-scriptfunctions ถูกเรียก (ตามลำดับ DOM)- Cleanup functions ถูกเก็บไว้
- เมื่อ Navigate ออก: cleanup functions ถูกเรียก
ข้อควรระวัง
⚠️ 1. Function ต้องเป็น Global
// ❌ ไม่สามารถเข้าถึง - scoped เข้า DOMContentLoaded
document.addEventListener('DOMContentLoaded', () => {
function initPage(element, data) { }
});
// ✅ Global function
function initPage(element, data) { }
// ✅ กำหนด global ชัดเจน
window.initPage = function(element, data) { };⚠️ 2. Memory Leaks
// ❌ ไม่ดี - ไม่มี cleanup สำหรับ timer
function initClock(element, data) {
setInterval(() => {
element.querySelector('#time').textContent = new Date().toLocaleTimeString();
}, 1000);
}
// ✅ ดี - มี cleanup
function initClock(element, data) {
const timer = setInterval(() => {
element.querySelector('#time').textContent = new Date().toLocaleTimeString();
}, 1000);
return () => clearInterval(timer);
}⚠️ 3. Async Functions
// ✅ Async ทำงานได้ - cleanup ยังรองรับ
async function initDashboard(element, data) {
const stats = await fetchStats();
renderStats(stats);
return () => {
// Cleanup
};
}⚠️ 4. ตรวจสอบ Element Existence
// ❌ อาจ error ถ้า element ไม่มี
function initForm(element, data) {
element.querySelector('#submit').addEventListener('click', submit);
}
// ✅ ตรวจสอบก่อน
function initForm(element, data) {
const submitBtn = element.querySelector('#submit');
if (!submitBtn) {
console.warn('ไม่พบปุ่ม Submit');
return;
}
submitBtn.addEventListener('click', submit);
}⚠️ 5. ชื่อ Function ไม่ซ้ำกัน
// ❌ ชื่อเดียวกัน - อันที่สองเขียนทับอันแรก
function initForm(element, data) { console.log('Form 1'); }
function initForm(element, data) { console.log('Form 2'); }
// ✅ ชื่อไม่ซ้ำกัน
function initLoginForm(element, data) { }
function initRegisterForm(element, data) { }Best Practices
1. ชื่อที่สื่อความหมาย
// ❌ ไม่ชัดเจน
function init(element, data) { }
// ✅ ชัดเจน
function initProductGallery(element, data) { }
function initCheckoutForm(element, data) { }2. Error Handling
function initChart(element, data) {
try {
const canvas = element.querySelector('#chart');
if (!canvas) throw new Error('ไม่พบ Canvas');
// Initialize
} catch (error) {
console.error('Chart init ล้มเหลว:', error);
element.innerHTML = '<p class="error">ไม่สามารถโหลด chart ได้</p>';
}
}3. แยกเป็น Helper Functions
function initDashboard(element, data) {
const cleanup1 = initStats(element, data.stats);
const cleanup2 = initChart(element, data.chart);
const cleanup3 = initActivityFeed(element, data.activity);
return () => {
cleanup1?.();
cleanup2?.();
cleanup3?.();
};
}
function initStats(element, stats) { /* ... */ }
function initChart(element, chartData) { /* ... */ }ที่เกี่ยวข้อง
- RouterManager - การตั้งค่า Route
- FormManager - การจัดการฟอร์ม
- ComponentManager - ระบบ Component