Now.js Framework Documentation
TemplateManager
TemplateManager
ภาพรวม
TemplateManager คือระบบ template และ data binding ใน Now.js Framework ประกอบด้วย:
- Template Loading - โหลด HTML template แบบ dynamic ผ่าน AJAX
- Data Binding - ผูกข้อมูลกับ DOM elements แบบ reactive
- JavaScript Initialization - เริ่มต้น JavaScript อัตโนมัติเมื่อ template โหลด
- Component Lifecycle - จัดการ cleanup เมื่อ template ถูกลบ
ใช้เมื่อ:
- ต้องการแยก HTML templates ออกจากหน้าหลัก
- ต้องการ reactive data binding ใน templates
- ต้องการ initialize JavaScript เมื่อ template โหลด
- ต้องการโครงสร้างโค้ดที่สะอาดและดูแลง่าย
ทำไมต้องใช้:
- ✅ 12 data directives สำหรับ binding
- ✅ โหลด templates แบบ dynamic ผ่าน AJAX
- ✅ Auto-initialize JavaScript functions
- ✅ รองรับ cleanup เมื่อ templates ถูกลบ
- ✅ มีความปลอดภัยในตัว (sanitization, validation)
Data Directives
TemplateManager มี 12 data directives สำหรับผูกข้อมูลกับ elements:
| Directive | คำอธิบาย | เอกสาร |
|---|---|---|
data-text |
ผูกเนื้อหาข้อความพร้อม formatters | data-text.md |
data-html |
ผูก HTML content พร้อม sanitization | data-html.md |
data-attr |
ผูก attributes (href, src ฯลฯ) | data-attr.md |
data-class |
ผูก CSS class (3 โหมด) | data-class.md |
data-style |
ผูก inline style | data-style.md |
data-if |
แสดงผลแบบมีเงื่อนไข | data-if.md |
data-for |
แสดงผลรายการ | data-for.md |
data-on |
จัดการ event (20+ modifiers) | data-on.md |
data-model |
Two-way binding ฟอร์ม | data-model.md |
data-checked |
ผูก checkbox/radio | data-checked.md |
data-container |
โหลด component แบบ dynamic | data-container.md |
data-script |
เริ่มต้น JavaScript | data-script.md |
ดู ดัชนี Template Directives สำหรับการอ้างอิงด่วน
การใช้งานพื้นฐาน
Template กับ Data Binding
<!-- profile.html -->
<main class="content" data-script="initProfile">
<h1 data-text="user.name"></h1>
<p data-text="user.email"></p>
<ul data-for="skill in user.skills">
<template>
<li data-text="skill"></li>
</template>
</ul>
<form data-form="editprofile">
<input type="text" name="name" data-model="user.name">
<button type="submit">บันทึก</button>
</form>
</main>Initialization Script
// main.js - Global function
function initProfile(element, data) {
console.log('โหลด Profile แล้ว!', element);
console.log('ข้อมูลจาก API:', data);
// Custom initialization
const input = element.querySelector('input[name="name"]');
input.addEventListener('focus', () => {
console.log('ฟิลด์ชื่อถูก focus');
});
// Return cleanup function (ไม่บังคับ)
return () => {
console.log('Cleanup Profile');
};
}การทำงาน:
- RouterManager โหลด
profile.html - TemplateManager ประมวลผล data directives ทั้งหมด
- ตรวจพบ
data-script="initProfile" - เรียก
window.initProfile(element, data) - เมื่อ navigate ออก เรียก cleanup function
ฟีเจอร์หลัก
1. Reactive Data Binding
การเปลี่ยนแปลงข้อมูลอัพเดท DOM อัตโนมัติ:
<span data-text="count"></span>
<button data-on="click:increment">+</button>let count = 0;
function increment() {
count++;
// DOM อัพเดทอัตโนมัติ
}2. Template Expressions
รองรับ expressions ใน bindings:
<!-- Text กับ formatters -->
<span data-text="price | currency:'THB'"></span>
<!-- Computed class -->
<div data-class="count > 0 ? 'has-items' : 'empty'"></div>
<!-- Conditional rendering -->
<div data-if="user.isAdmin && permissions.edit">
ส่วนควบคุมแอดมิน
</div>3. Event Handling
Event binding แบบ declarative พร้อม modifiers:
<!-- Basic click -->
<button data-on="click:save">บันทึก</button>
<!-- กับ modifiers -->
<form data-on="submit.prevent:handleSubmit">
<input data-on="keydown.enter:search">
<div data-on="click.self:close">4. Auto-Initialization
Templates ที่มี data-script จะถูก initialize อัตโนมัติ:
<div class="dashboard" data-script="initDashboard">
<div id="chart"></div>
</div>function initDashboard(element, data) {
const chart = new Chart(element.querySelector('#chart'), {
type: 'bar',
data: data.chartData
});
return () => chart.destroy();
}5. Cleanup Functions
Return function เพื่อ cleanup เมื่อ template ถูกลบ:
function initTimer(element, data) {
const timer = setInterval(() => {
element.querySelector('#time').textContent = new Date().toLocaleTimeString();
}, 1000);
// ถูกเรียกเมื่อ navigate ออก
return () => clearInterval(timer);
}การใช้งานขั้นสูง
รับข้อมูลจาก API
เมื่อใช้กับ RouterManager ที่มี data-load-api:
// Router configuration
routes: {
'/dashboard': {
template: 'dashboard.html',
title: 'Dashboard',
'data-load-api': 'api/dashboard/stats'
}
}function initDashboard(element, data) {
// data มี API response
console.log(data); // { totalUsers: 150, activeUsers: 89, ... }
renderStats(data);
}หลาย Scripts
Templates สามารถมีหลาย data-script attributes:
<div class="page">
<main data-script="initMainContent">...</main>
<aside data-script="initSidebar">...</aside>
<footer data-script="initFooter">...</footer>
</div>Functions ถูกเรียกตามลำดับ DOM (บนลงล่าง)
Nested Templates
Templates สามารถมี templates อื่นๆ ได้:
<div data-container="'components/' + currentComponent + '.html'"></div>ดู data-container.md สำหรับรายละเอียด
ข้อควรระวัง
⚠️ 1. Function ต้องเป็น Global
// ❌ ไม่ทำงาน - Function อยู่ใน module scope
document.addEventListener('DOMContentLoaded', () => {
function initProfile(element, data) { }
});
// ✅ ถูก - Global function
function initProfile(element, data) { }
// ✅ ถูก - กำหนด global ชัดเจน
window.initProfile = function(element, data) { };⚠️ 2. Memory Leaks
// ❌ ไม่ดี - ไม่มี cleanup
function initTimer(element, data) {
setInterval(() => { /* ทำงานตลอดไป */ }, 1000);
}
// ✅ ดี - มี cleanup
function initTimer(element, data) {
const timer = setInterval(() => { /* ... */ }, 1000);
return () => clearInterval(timer);
}⚠️ 3. ตรวจสอบ Element ก่อน
// ❌ อาจ error
function initForm(element, data) {
element.querySelector('#input').value = data.value;
}
// ✅ ตรวจสอบก่อน
function initForm(element, data) {
const input = element.querySelector('#input');
if (input) input.value = data.value || '';
}แนวปฏิบัติที่ดี
1. ชื่อ Function ที่ชัดเจน
// ✅ ดี
function initUserProfileForm(element, data) { }
function initSalesChart(element, data) { }
function initProductGallery(element, data) { }2. แยก Helper Functions
function initDashboard(element, data) {
const cleanup1 = initStats(element, data.stats);
const cleanup2 = initChart(element, data.chart);
return () => {
cleanup1?.();
cleanup2?.();
};
}3. Event Delegation
function initList(element, data) {
const list = element.querySelector('#list');
const handleClick = (e) => {
if (e.target.matches('.btn-delete')) {
handleDelete(e.target.dataset.id);
}
};
list.addEventListener('click', handleClick);
return () => list.removeEventListener('click', handleClick);
}4. Error Handling
function initDataTable(element, data) {
try {
const table = element.querySelector('#table');
if (!table) throw new Error('ไม่พบ Table');
// Initialize...
} catch (error) {
console.error('Init ล้มเหลว:', error);
element.innerHTML = '<p class="error">โหลดล้มเหลว</p>';
}
}การผสานระบบ
กับ FormManager
<form data-form="editprofile" data-script="initProfileForm" data-load-api="api/users/get">
<!-- FormManager จัดการฟอร์ม, data-script เพิ่ม logic เอง -->
</form>กับ ComponentManager
<div data-component="sidebar" data-script="initSidebar"></div>กับ ApiComponent
<div data-api-component="userList" data-script="initUserList" data-api-url="api/users/list">
</div>เอกสารที่เกี่ยวข้อง
เอกสาร Directive
- ดัชนี Template Directives - อ้างอิงด่วนสำหรับทุก directives
- data-script - รายละเอียดการ initialize script
ระบบอื่นๆ
- RouterManager - Routing และการโหลด template
- FormManager - การจัดการฟอร์ม
- ComponentManager - ระบบ Component
- ApiComponent - Components ที่ขับเคลื่อนด้วย API