Common errors, debugging tips, and console fixes for TinyPine.js v1.3.0
Problem: You're using a directive that doesn't exist or is misspelled.
Solution:
<!-- ❌ Wrong -->
<div t-visible="isOpen">
<!-- ✅ Correct -->
<div t-show="isOpen"></div>
</div>Valid Directives:
t-data,t-text,t-html,t-show,t-bind,t-classt-for,t-model,t-click,t-ref,t-validatet-fetch,t-await,t-route,t-init,t-effect,t-destroy
Problem: Invalid JavaScript expression in directive.
Common Causes:
<!-- ❌ Syntax error -->
<div t-show="count > 5 &&">
<!-- ❌ Undefined variable -->
<div t-text="userName">
<!-- userName not in t-data -->
<!-- ✅ Correct -->
<div t-data="{ count: 0, userName: 'John' }">
<div t-show="count > 5 && userName">
<div t-text="userName"></div>
</div>
</div>
</div>
</div>Debug Steps:
- Check browser console for exact error
- Verify variable exists in scope
- Test expression in console
Problem: t-for directive used on non-array data.
Solution:
<!-- ❌ Wrong -->
<div t-data="{ items: {} }">
<li t-for="item in items">
<!-- ✅ Correct -->
<div t-data="{ items: [] }">
<li t-for="item in items"></li>
</div>
</li>
</div>Problem: Input value doesn't sync with state.
Common Causes:
- Property not defined in
t-data - Typo in property name
- Using
t-modeloutsidet-datascope
Solution:
<!-- ❌ Property not defined -->
<div t-data="{ count: 0 }">
<input t-model="name" />
<!-- name not in t-data -->
</div>
<!-- ✅ Correct -->
<div t-data="{ count: 0, name: '' }">
<input t-model="name" />
</div>Problem: Click event doesn't trigger state update.
Common Causes:
<!-- ❌ Missing parentheses -->
<button t-click="increment">
<!-- ❌ Method not defined -->
<button t-click="save()"> <!-- save not in methods -->
<!-- ✅ Correct with state update -->
<button t-click="count++">
<!-- ✅ Correct with method -->
<div t-data="{ count: 0, methods: { increment() { this.count++; } } }">
<button t-click="increment()">
</div>Problem: Using t-validate without t-model.
Solution:
<!-- ❌ Wrong -->
<input t-validate="required|email" />
<!-- ✅ Correct -->
<input t-model="email" t-validate="required|email" />Problem: Route changes but elements don't show/hide.
Common Causes:
- Hash navigation not used (
#/route) - Router not initialized
- Route name mismatch
Solution:
<!-- ❌ Wrong -->
<a href="/about">About</a>
<div t-route="about-page">
<!-- ✅ Correct -->
<a href="#/about">About</a>
<div t-route="about">
<script>
TinyPine.router({ default: "home" });
</script>
</div>
</div>TinyPine.debug = true;
// or
TinyPine.enableDebug();What you'll see:
- State changes
- Directive processing
- Expression evaluation results
- Router navigation
- Validation results
// Get element's state
const el = document.querySelector("[t-data]");
const state = el._tinypineState;
console.log(state);
// Check context
const context = el._tinypineContext;
console.log(context.methods);
console.log(context.$refs);const stores = TinyPine.getAllStores();
console.log(stores);
const auth = TinyPine.getStore("auth");
console.log(auth);const form = document.querySelector("tp-form");
const scope = form.closest("[t-data]");
// Validate all fields
const isValid = TinyPine.forms.validate(scope);
console.log("Valid:", isValid);
// Get form data
const data = TinyPine.forms.getData(scope);
console.log("Data:", data);
// Check errors
const errors = scope._tinypineState.$errors;
console.log("Errors:", errors);// Get current route
const currentRoute = TinyPine.router.getCurrent();
console.log("Current:", currentRoute);
// Get route params
const params = TinyPine._routerState.currentParams;
console.log("Params:", params);
// Navigate programmatically
TinyPine.router.push("user", { id: "123" });Cause: Store module not loaded or stores not initialized.
Solution:
// Initialize stores before using them
TinyPine.store("auth", { user: null, token: null });
// Then start app
TinyPine.start("#app");Cause: Invalid t-fetch expression.
Solution:
<!-- ❌ Wrong -->
<div t-fetch="apiData">
<!-- ✅ Correct -->
<div t-fetch="'/api/data'">
<!-- or -->
<div t-data="{ url: '/api/data' }">
<div t-fetch="url"></div>
</div>
</div>
</div>Cause: Route guard returned false.
Solution:
TinyPine.router({
routes: {
admin: {
beforeEnter: (route, params) => {
const auth = TinyPine.getStore("auth");
if (!auth.isAdmin) {
console.warn("Admin access required");
return false; // Block navigation
}
return true; // Allow
},
},
},
});Solution: Use :key binding
<!-- ❌ Slow (re-renders everything) -->
<li t-for="item in items">
<!-- ✅ Fast (keyed diffing) -->
</li>
<li t-for="item in items" :key="item.id"></li>Solution: Batch updates
// ❌ Multiple updates
count++;
count++;
count++;
// ✅ Single update
count += 3;Solution: Use lifecycle hooks
{
timer: null,
mounted() {
this.timer = setInterval(() => {
this.count++;
}, 1000);
},
beforeUnmount() {
clearInterval(this.timer);
}
}Use TinyPine DevTools:
TinyPine.devtools();Features:
- Live state inspector
- Store viewer
- Event timeline
- Performance metrics
- Check console first - Most errors show detailed messages
- Enable debug mode -
TinyPine.debug = true - Inspect element state - Use
el._tinypineState - Test expressions in console - Verify syntax
- Check GitHub issues - Common problems may be documented
- Is
TinyPine.start()called? - Are all properties defined in
t-data? - Is the directive name spelled correctly?
- Are expressions valid JavaScript?
- Is the element inside a
t-datascope? - Are required attributes present? (e.g.,
t-modelfort-validate) - Is the browser console showing any errors?
- Is debug mode enabled for detailed logs?
Last Updated: v1.3.0 Need more help? Open an issue on GitHub