data - Loaded Data Access
- Type:
Object - Description: Contains values returned by
+load.jsfiles in the current route - Global: Yes (available as
datain templates) - API Property:
api.data
Basic Usage
<!-- Using the global property -->
<h1><%= data.siteName %></h1>
<!-- Using the API property -->
<h1><%= api.data.siteName %></h1>
Loading Data
Data is loaded through +load.js files in your route hierarchy:
pb_hooks/
pages/
+load.js # Global data
products/
+load.js # Products data
[id]/
+load.js # Single product data
index.ejs # Template using data
Note: Only the leaf-level
+load.jsfile is executed. For cascading data loading, use Middleware.
Example Loaders
Root Level Data
/** @type {import('pocketpages').PageDataLoaderFunc} */
module.exports = function (api) {
return {
siteName: 'My Store',
navigation: [
{ title: 'Home', url: '/' },
{ title: 'Products', url: '/products' },
],
}
}
Product List Data
/** @type {import('pocketpages').PageDataLoaderFunc} */
module.exports = function (api) {
const categories = $app.findRecordsByFilter('categories', {
filter: 'active = true',
sort: 'name',
})
return { categories }
}
Single Product Data
/** @type {import('pocketpages').PageDataLoaderFunc} */
module.exports = function (api) {
const { findRecordByFilter, params, response } = api
const product = findRecordByFilter('products', {
filter: `id = "${params.id}"`,
})
if (!product) {
response.status(404)
return { error: 'Product not found' }
}
return { product }
}
Template Usage
Basic Example
<!-- Navigation from root data -->
<nav>
<% data.navigation.forEach(item => { %>
<a href="/?originalUrl=https%3A%2F%2Fpocketpages.dev%2F%26quot%3B%26lt%3B%25%3D%2520item.url%2520%25%26gt%3B%26quot%3B%26gt%3B%26lt%3B%25%3D%2520item.title%2520%25%26gt%3B%26lt%3B%2Fa%26gt%3B%2520%2520%26lt%3B%25%2520%257D)%2520%25%26gt%3B%26lt%3B%2Fnav%26gt%3B%253C%2Fcode">
Complete Example
<!DOCTYPE html>
<html>
<head>
<title><%= data.product.name %> | <%= data.siteName %></title>
</head>
<body>
<!-- Navigation -->
<nav>
<% data.navigation.forEach(item => { %>
<a href="/?originalUrl=https%3A%2F%2Fpocketpages.dev%2F%26quot%3B%26lt%3B%25%3D%2520item.url%2520%25%26gt%3B%26quot%3B%26gt%3B%26lt%3B%25%3D%2520item.title%2520%25%26gt%3B%26lt%3B%2Fa%26gt%3B%2520%2520%2520%2520%26lt%3B%25%2520%257D)%2520%25%26gt%3B%2520%2520%26lt%3B%2Fnav%26gt%3B%2520%2520%26lt%3B!--%2520Categories%2520--%26gt%3B%2520%2520%26lt%3Baside%26gt%3B%2520%2520%2520%2520%26lt%3Bh2%26gt%3BCategories%26lt%3B%2Fh2%26gt%3B%2520%2520%2520%2520%26lt%3Bul%26gt%3B%2520%2520%2520%2520%2520%2520%26lt%3B%25%2520data.categories.forEach(cat%2520%3D%26gt%3B%2520%257B%2520%25%26gt%3B%2520%2520%2520%2520%2520%2520%2520%2520%26lt%3Bli%26gt%3B%26lt%3B%25%3D%2520cat.name%2520%25%26gt%3B%26lt%3B%2Fli%26gt%3B%2520%2520%2520%2520%2520%2520%26lt%3B%25%2520%257D)%2520%25%26gt%3B%2520%2520%2520%2520%26lt%3B%2Ful%26gt%3B%2520%2520%26lt%3B%2Faside%26gt%3B%2520%2520%26lt%3B!--%2520Product%2520Details%2520--%26gt%3B%2520%2520%26lt%3B%25%2520if%2520(data.error)%2520%257B%2520%25%26gt%3B%2520%2520%2520%2520%26lt%3Bh1%26gt%3BError%3A%2520%26lt%3B%25%3D%2520data.error%2520%25%26gt%3B%26lt%3B%2Fh1%26gt%3B%2520%2520%26lt%3B%25%2520%257D%2520else%2520%257B%2520%25%26gt%3B%2520%2520%2520%2520%26lt%3Bmain%26gt%3B%2520%2520%2520%2520%2520%2520%26lt%3Bh1%26gt%3B%26lt%3B%25%3D%2520data.product.name%2520%25%26gt%3B%26lt%3B%2Fh1%26gt%3B%2520%2520%2520%2520%2520%2520%26lt%3Bp%26gt%3B%26lt%3B%25%3D%2520data.product.description%2520%25%26gt%3B%26lt%3B%2Fp%26gt%3B%2520%2520%2520%2520%26lt%3B%2Fmain%26gt%3B%2520%2520%26lt%3B%25%2520%257D%2520%25%26gt%3B%26lt%3B%2Fbody%26gt%3B%26lt%3B%2Fhtml%26gt%3B%253C%2Fcode">
Best Practices
Structured Data Organization
// Good: Clear structure return { products: productList, categories: categoryList, } // Avoid: Flat structure return { productList: products, productCount: count, productCategories: categories, }Error Handling
module.exports = function (api) { try { const data = $app.dao().findRecordById(/*...*/) return { data } } catch (error) { api.response.status(500) return { error: 'Failed to load data' } } }Type Safety
/** @type {import('pocketpages').PageDataLoaderFunc} */ module.exports = function (api) { return { timestamp: Date.now(), version: '1.0.0', } }
Important Notes
- Data is loaded fresh for each request
- Synchronous loading only - no async operations
- More specific routes can override parent data
- Use
stringify(data)for debugging - Only leaf-level
+load.jsfiles are executed