8.1 KiB
8.1 KiB
Alpine.js Page Template - Quick Reference
✅ Correct Page Structure
// static/admin/js/your-page.js
// 1. Setup logging (optional but recommended)
const YOUR_PAGE_LOG_LEVEL = 3;
const yourPageLog = {
error: (...args) => YOUR_PAGE_LOG_LEVEL >= 1 && console.error('❌ [YOUR_PAGE ERROR]', ...args),
warn: (...args) => YOUR_PAGE_LOG_LEVEL >= 2 && console.warn('⚠️ [YOUR_PAGE WARN]', ...args),
info: (...args) => YOUR_PAGE_LOG_LEVEL >= 3 && console.info('ℹ️ [YOUR_PAGE INFO]', ...args),
debug: (...args) => YOUR_PAGE_LOG_LEVEL >= 4 && console.log('🔍 [YOUR_PAGE DEBUG]', ...args)
};
// 2. Create your Alpine.js component
function yourPageComponent() {
return {
// ✅ CRITICAL: Inherit base layout functionality
...data(),
// ✅ CRITICAL: Set page identifier
currentPage: 'your-page',
// Your page-specific state
items: [],
loading: false,
error: null,
// ✅ CRITICAL: Proper initialization with guard
async init() {
yourPageLog.info('=== YOUR PAGE INITIALIZING ===');
// Prevent multiple initializations
if (window._yourPageInitialized) {
yourPageLog.warn('Page already initialized, skipping...');
return;
}
window._yourPageInitialized = true;
// Load your data
await this.loadData();
yourPageLog.info('=== YOUR PAGE INITIALIZATION COMPLETE ===');
},
// Your methods
async loadData() {
yourPageLog.info('Loading data...');
this.loading = true;
this.error = null;
try {
const startTime = Date.now();
// ✅ CRITICAL: Use lowercase apiClient
const response = await apiClient.get('/your/endpoint');
const duration = Date.now() - startTime;
this.items = response.items || [];
yourPageLog.info(`Data loaded in ${duration}ms`, {
count: this.items.length
});
} catch (error) {
yourPageLog.error('Failed to load data:', error);
this.error = error.message;
Utils.showToast('Failed to load data', 'error');
} finally {
this.loading = false;
}
},
// Format date helper (if needed)
formatDate(dateString) {
if (!dateString) return '-';
return Utils.formatDate(dateString);
},
// Your other methods...
};
}
yourPageLog.info('Your page module loaded');
🎯 Checklist for New Pages
HTML Template
{# app/templates/admin/your-page.html #}
{% extends "admin/base.html" %}
{% block title %}Your Page{% endblock %}
{# ✅ CRITICAL: Link to your Alpine.js component #}
{% block alpine_data %}yourPageComponent(){% endblock %}
{% block content %}
<!-- Your page content -->
{% endblock %}
{% block extra_scripts %}
{# ✅ CRITICAL: Load your JavaScript file #}
<script src="{{ url_for('static', path='admin/js/your-page.js') }}"></script>
{% endblock %}
JavaScript File Checklist
- ✅ Logging setup (optional)
- ✅ Function name matches
alpine_datain template - ✅
...data(),at start of return object - ✅
currentPage: 'your-page'set - ✅ Initialization guard in
init() - ✅ Use lowercase
apiClientfor API calls - ✅ Use your custom logger (not
Logger) - ✅ Performance tracking with
Date.now()(optional) - ✅ Module loaded log at end
❌ Common Mistakes to Avoid
1. Missing Base Inheritance
// ❌ WRONG
function myPage() {
return {
items: [],
// Missing ...data()
};
}
// ✅ CORRECT
function myPage() {
return {
...data(), // Must be first!
items: [],
};
}
2. Wrong API Client Name
// ❌ WRONG - Capital letters
await ApiClient.get('/endpoint');
await API_CLIENT.get('/endpoint');
// ✅ CORRECT - lowercase
await apiClient.get('/endpoint');
3. Missing Init Guard
// ❌ WRONG
async init() {
await this.loadData();
}
// ✅ CORRECT
async init() {
if (window._myPageInitialized) return;
window._myPageInitialized = true;
await this.loadData();
}
4. Missing currentPage
// ❌ WRONG
return {
...data(),
items: [],
// Missing currentPage
};
// ✅ CORRECT
return {
...data(),
currentPage: 'my-page', // Must set this!
items: [],
};
🔧 API Client Pattern
GET Request
try {
const response = await apiClient.get('/endpoint');
this.data = response;
} catch (error) {
console.error('Failed:', error);
Utils.showToast('Failed to load', 'error');
}
POST Request
try {
const response = await apiClient.post('/endpoint', {
name: 'value',
// ... data
});
Utils.showToast('Created successfully', 'success');
} catch (error) {
console.error('Failed:', error);
Utils.showToast('Failed to create', 'error');
}
PUT Request
try {
const response = await apiClient.put('/endpoint/123', {
name: 'updated value'
});
Utils.showToast('Updated successfully', 'success');
} catch (error) {
console.error('Failed:', error);
Utils.showToast('Failed to update', 'error');
}
DELETE Request
try {
await apiClient.delete('/endpoint/123');
Utils.showToast('Deleted successfully', 'success');
await this.reloadData();
} catch (error) {
console.error('Failed:', error);
Utils.showToast('Failed to delete', 'error');
}
🎨 Common UI Patterns
Loading State
async loadData() {
this.loading = true;
try {
const data = await apiClient.get('/endpoint');
this.items = data;
} finally {
this.loading = false;
}
}
Error Handling
async loadData() {
this.loading = true;
this.error = null;
try {
const data = await apiClient.get('/endpoint');
this.items = data;
} catch (error) {
this.error = error.message;
Utils.showToast('Failed to load', 'error');
} finally {
this.loading = false;
}
}
Refresh/Reload
async refresh() {
console.info('Refreshing...');
await this.loadData();
Utils.showToast('Refreshed successfully', 'success');
}
📚 Available Utilities
From init-alpine.js (via ...data())
this.dark- Dark mode statethis.toggleTheme()- Toggle themethis.isSideMenuOpen- Side menu statethis.toggleSideMenu()- Toggle side menuthis.closeSideMenu()- Close side menuthis.isNotificationsMenuOpen- Notifications menu statethis.toggleNotificationsMenu()- Toggle notificationsthis.closeNotificationsMenu()- Close notificationsthis.isProfileMenuOpen- Profile menu statethis.toggleProfileMenu()- Toggle profile menuthis.closeProfileMenu()- Close profile menuthis.isPagesMenuOpen- Pages menu statethis.togglePagesMenu()- Toggle pages menu
From Utils (global)
Utils.showToast(message, type, duration)- Show toast notificationUtils.formatDate(dateString)- Format date for displayUtils.confirm(message, title)- Show confirmation dialog (if available)
From apiClient (global)
apiClient.get(url)- GET requestapiClient.post(url, data)- POST requestapiClient.put(url, data)- PUT requestapiClient.delete(url)- DELETE request
🚀 Quick Start Template Files
Copy these to create a new page:
- Copy
dashboard.js→ rename toyour-page.js - Replace function name:
adminDashboard()→yourPageComponent() - Update logging prefix:
dashLog→yourPageLog - Update init flag:
_dashboardInitialized→_yourPageInitialized - Update
currentPage:'dashboard'→'your-page' - Replace data loading logic with your endpoints
- Update HTML template to use your function name
Done! ✅