Update git remote domain from privategit.hanson.xyz to git.internal.hanson.xyz, remove port 3322
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,7 @@ SYNOPSIS
|
||||
class User_Card extends Jqhtml_Component {
|
||||
async on_load() {
|
||||
// Load async data - ONLY modify this.data
|
||||
this.data = await fetch('/api/user/' + this.args.id)
|
||||
.then(r => r.json());
|
||||
this.data = await User_Controller.get({id: this.args.id});
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
@@ -43,6 +42,81 @@ DESCRIPTION
|
||||
- Double-render pattern for loading states
|
||||
- No build configuration required (auto-discovered)
|
||||
|
||||
COMPONENT COMPLEXITY TIERS
|
||||
Three tiers guide which patterns to use for a new component:
|
||||
|
||||
Static Components (template-only, no JS file):
|
||||
Pure display from this.args. No lifecycle hooks needed.
|
||||
Use for: badges, labels, static cards, layout wrappers.
|
||||
|
||||
<Define:Status_Badge>
|
||||
<span class="badge <%= this.args.css_class %>">
|
||||
<%= this.args.label %>
|
||||
</span>
|
||||
</Define:Status_Badge>
|
||||
|
||||
Simple Components (on_load + reload):
|
||||
Fetch data in on_load(), re-fetch with reload() when this.args change.
|
||||
Most common pattern. Framework handles caching and re-render.
|
||||
|
||||
class User_List extends Jqhtml_Component {
|
||||
on_create() {
|
||||
this.data.users = [];
|
||||
}
|
||||
async on_load() {
|
||||
this.data = await User_Controller.list({
|
||||
filter: this.args.filter
|
||||
});
|
||||
}
|
||||
on_ready() {
|
||||
this.$sid('filter_btn').on('click', () => {
|
||||
this.args.filter = 'active';
|
||||
this.reload(); // Re-fetches via on_load()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Complex Components (on_load + jQuery DOM manipulation):
|
||||
Use on_load() for initial/cached data, then jQuery for incremental
|
||||
mutations after initialization. Avoids unnecessary network round-trips
|
||||
and preserves user state (selections, scroll position, input).
|
||||
|
||||
class Chat_Widget extends Jqhtml_Component {
|
||||
async on_load() {
|
||||
this.data = await Chat_Controller.get_messages({
|
||||
channel: this.args.channel
|
||||
});
|
||||
}
|
||||
on_ready() {
|
||||
// Incremental updates via DOM, not reload()
|
||||
this.socket = new WebSocket(this.args.ws_url);
|
||||
this.socket.onmessage = (e) => {
|
||||
const msg = JSON.parse(e.data);
|
||||
this.$sid('messages').append(
|
||||
'<div class="message">' + Rsx.escape(msg.text) + '</div>'
|
||||
);
|
||||
};
|
||||
}
|
||||
on_stop() {
|
||||
this.socket.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
this.state Convention:
|
||||
this.state is not a framework property - it has no special behavior.
|
||||
Use it as convention for mutable UI state that changes after
|
||||
initialization, distinct from this.data (immutable after on_load).
|
||||
|
||||
on_create() {
|
||||
this.state = { selected_ids: [], is_expanded: false };
|
||||
}
|
||||
on_ready() {
|
||||
this.$sid('toggle').on('click', () => {
|
||||
this.state.is_expanded = !this.state.is_expanded;
|
||||
this.$sid('panel').toggle(this.state.is_expanded);
|
||||
});
|
||||
}
|
||||
|
||||
SEMANTIC-FIRST DESIGN
|
||||
JQHTML is designed for mechanical thinkers who think structurally
|
||||
rather than visually. Components represent logical concepts, not
|
||||
@@ -553,8 +627,7 @@ DOUBLE-RENDER PATTERN
|
||||
}
|
||||
|
||||
async on_load() {
|
||||
this.data.products = await fetch('/api/products')
|
||||
.then(r => r.json());
|
||||
this.data.products = await Product_Controller.list();
|
||||
// Automatic re-render happens after this completes
|
||||
}
|
||||
|
||||
@@ -581,7 +654,7 @@ LOADING STATE PATTERN (CRITICAL)
|
||||
this.data.state = {loading: true};
|
||||
this.render(); // WRONG: Manual render call
|
||||
|
||||
const response = await $.ajax({...}); // WRONG: $.ajax()
|
||||
const response = await $.ajax({url: '...', ...}); // WRONG: $.ajax()
|
||||
|
||||
if (response.success) {
|
||||
this.data = {
|
||||
@@ -684,8 +757,7 @@ JAVASCRIPT COMPONENT CLASS
|
||||
async on_load() {
|
||||
// Fetch data - NO DOM manipulation allowed!
|
||||
// ONLY update this.data
|
||||
this.data.products = await fetch('/api/products')
|
||||
.then(r => r.json());
|
||||
this.data.products = await Product_Controller.list();
|
||||
// Template re-renders automatically with new data
|
||||
}
|
||||
|
||||
@@ -1360,9 +1432,9 @@ EXAMPLES
|
||||
class Product_Card extends Jqhtml_Component {
|
||||
async on_load() {
|
||||
// Load product data
|
||||
const id = this.args.product_id;
|
||||
this.data = await fetch(`/api/products/${id}`)
|
||||
.then(r => r.json());
|
||||
this.data = await Product_Controller.get({
|
||||
id: this.args.product_id
|
||||
});
|
||||
// Template re-renders automatically with data
|
||||
}
|
||||
|
||||
@@ -1399,8 +1471,7 @@ EXAMPLES
|
||||
|
||||
class Todo_List extends Jqhtml_Component {
|
||||
async on_load() {
|
||||
this.data.todos = await fetch('/api/todos')
|
||||
.then(r => r.json());
|
||||
this.data = await Todo_Controller.list();
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
@@ -1438,15 +1509,9 @@ EXAMPLES
|
||||
}
|
||||
|
||||
async submit() {
|
||||
const data = {
|
||||
await Contact_Controller.send({
|
||||
email: this.$sid('email').val(),
|
||||
message: this.$sid('message').val(),
|
||||
};
|
||||
|
||||
await fetch('/contact', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
this.$.html('<p>Thank you!</p>');
|
||||
|
||||
Reference in New Issue
Block a user