diff --git a/docs/CLAUDE.dist.md b/docs/CLAUDE.dist.md index da63048f9..182d25e7c 100644 --- a/docs/CLAUDE.dist.md +++ b/docs/CLAUDE.dist.md @@ -668,6 +668,74 @@ on_create() { **Double-render**: If `on_load()` modifies `this.data`, component renders twice (defaults → populated). +### Component API - CRITICAL FOR LLM AGENTS + +This section clarifies common misunderstandings. Read carefully. + +**DOM Access Methods:** + +| Method | Returns | Purpose | +|--------|---------|---------| +| `this.$` | jQuery | Root element of component (stable, survives redraws) | +| `this.$sid('name')` | jQuery | Child element with `$sid="name"` (always returns jQuery, even if empty) | +| `this.sid('name')` | Component or null | Child component instance (null if not found or not a component) | +| `this.$.find('.class')` | jQuery | Standard jQuery find (use when `$sid` isn't appropriate) | + +**WRONG:** `this.$el` - This does not exist. Use `this.$` + +**The reload() Paradigm - MANDATORY:** + +``` +reload() = on_load() → render() → on_ready() +render() = template redraw only (NO on_ready) +``` + +**LLM agents must ALWAYS use `reload()`, NEVER call `render()` directly.** + +When you need to refresh a component after a mutation (add, edit, delete), call `this.reload()`. Yes, this makes another server call via `on_load()`. This is intentional. The extra round-trip is acceptable - our server is fast and the paradigm simplicity is worth it. + +**WRONG approach (do NOT do this):** +```javascript +// ❌ BAD - Trying to be "efficient" by skipping server round-trip +async add_item() { + const new_item = await Controller.add({name: 'Test'}); + this.data.items.push(new_item); // ERROR: Cannot modify this.data outside on_load + this.render(); // WRONG: Event handlers will break, on_ready won't run +} +``` + +**CORRECT approach:** +```javascript +// ✅ GOOD - Clean, consistent, reliable +async add_item() { + await Controller.add({name: 'Test'}); + this.reload(); // Calls on_load() to refresh this.data, then on_ready() for handlers +} +``` + +**Event Handlers - Set Up in on_ready():** + +Event handlers must be registered in `on_ready()`. Since `on_ready()` runs after every `reload()`, handlers automatically reattach when the DOM is redrawn. + +```javascript +on_ready() { + this.$sid('save_btn').click(() => this.save()); + this.$sid('delete_btn').click(() => this.delete()); +} +``` + +**WRONG:** Event delegation to avoid `reload()`. If you find yourself writing `this.$.on('click', '[data-sid="btn"]', handler)` to "survive" render calls, you're doing it wrong. Use `reload()` and let `on_ready()` reattach handlers. + +**this.data Modification Rules (ENFORCED):** + +- `on_create()`: Set defaults only (e.g., `this.data.items = []`) +- `on_load()`: Fetch and assign from server (e.g., `this.data.items = await Controller.list()`) +- **Everywhere else**: Read-only. Attempting to modify `this.data` outside these methods throws an error. + +**on_render() - LLM Should Not Use:** + +`on_render()` exists for human developers doing performance optimization. LLM agents should pretend it doesn't exist. Use `on_ready()` for all post-render DOM work. + ### Loading Pattern ```javascript