Data Binding
Data binding is the process of connecting your template elements to data sources in Canvelete (opens in a new tab), enabling automatic updates when data changes. Canvelete provides powerful data binding capabilities that make it easy to create responsive, data-driven designs.
Understanding Data Binding
Data binding creates a live connection between your template elements and data sources. When the underlying data changes, the visual elements automatically update to reflect those changes.
Types of Data Binding
One-Way Binding
Data flows from the source to the template element:
// Simple one-way binding
"{{user.name}}" // Displays the user's name
// With default values
"{{user.name || 'Guest User'}}" // Shows 'Guest User' if name is emptyTwo-Way Binding
Data flows in both directions (for interactive elements):
// Input field with two-way binding
{
"type": "input",
"value": "{{user.email}}",
"onChange": "updateUser.email"
}Computed Binding
Derived values calculated from other data:
// Computed full name
"{{user.firstName + ' ' + user.lastName}}"
// Computed discount percentage
"{{((originalPrice - salePrice) / originalPrice * 100).toFixed(1)}}%"Data Source Configuration
JSON Data Sources
Connect to static or dynamic JSON data:
// Static JSON data
{
"dataSource": {
"type": "json",
"data": {
"products": [
{"id": 1, "name": "Product A", "price": 29.99},
{"id": 2, "name": "Product B", "price": 39.99}
]
}
}
}API Data Sources
Connect to REST APIs for live data:
// API configuration
{
"dataSource": {
"type": "api",
"url": "https://api.example.com/products",
"method": "GET",
"headers": {
"Authorization": "Bearer {{apiToken}}",
"Content-Type": "application/json"
},
"refreshInterval": 300000 // 5 minutes
}
}Database Connections
Connect directly to databases:
// Database configuration
{
"dataSource": {
"type": "database",
"connection": "postgresql://user:pass@host:5432/db",
"query": "SELECT * FROM products WHERE category = $1",
"parameters": ["{{selectedCategory}}"]
}
}CSV/Spreadsheet Data
Import data from CSV files or spreadsheets:
// CSV data source
{
"dataSource": {
"type": "csv",
"url": "https://example.com/data.csv",
"delimiter": ",",
"headers": true,
"mapping": {
"productName": "Product Name",
"productPrice": "Price (USD)"
}
}
}Binding Syntax
Basic Variable Binding
// Simple property access
"{{user.name}}"
"{{product.price}}"
"{{order.items[0].quantity}}"
// Nested object access
"{{user.profile.address.city}}"
"{{company.departments[0].manager.name}}"Array and Object Iteration
// Iterate through arrays
"{{#each products}}
<div class='product'>
<h3>{{name}}</h3>
<p>${{price}}</p>
</div>
{{/each}}"
// Iterate with index
"{{#each users as |user index|}}
{{index + 1}}. {{user.name}}
{{/each}}"
// Iterate through object properties
"{{#each user}}
{{@key}}: {{this}}
{{/each}}"Conditional Binding
// Simple conditions
"{{#if user.isActive}}
Active User
{{else}}
Inactive User
{{/if}}"
// Multiple conditions
"{{#if user.role === 'admin'}}
Administrator
{{else if user.role === 'moderator'}}
Moderator
{{else}}
Regular User
{{/if}}"
// Inline conditions
"{{user.isActive ? 'Active' : 'Inactive'}}"Data Filters and Transformations
Text Filters
// Case transformations
"{{user.name | uppercase}}" // JOHN DOE
"{{user.name | lowercase}}" // john doe
"{{user.name | titlecase}}" // John Doe
"{{user.name | camelcase}}" // johnDoe
// Text manipulation
"{{description | truncate:100}}" // Limit to 100 characters
"{{content | stripHtml}}" // Remove HTML tags
"{{text | slugify}}" // Convert to URL-friendly slugNumber Filters
// Formatting
"{{price | currency:'USD'}}" // $29.99
"{{percentage | percent:2}}" // 15.25%
"{{fileSize | bytes}}" // 1.2 MB
// Mathematical operations
"{{value | round:2}}" // Round to 2 decimal places
"{{number | abs}}" // Absolute value
"{{price | multiply:1.08}}" // Add 8% taxDate Filters
// Date formatting
"{{createdAt | date:'YYYY-MM-DD'}}" // 2024-01-15
"{{updatedAt | date:'MMM DD, YYYY'}}" // Jan 15, 2024
"{{timestamp | time:'HH:mm'}}" // 14:30
// Relative dates
"{{createdAt | timeAgo}}" // 2 hours ago
"{{dueDate | timeUntil}}" // in 3 daysArray Filters
// Array operations
"{{products | length}}" // Number of items
"{{prices | sum}}" // Total of all prices
"{{ratings | average}}" // Average rating
"{{products | first}}" // First item
"{{products | last}}" // Last item
// Filtering arrays
"{{products | where:'category','Electronics'}}"
"{{users | where:'isActive',true}}"
"{{items | sortBy:'price'}}"Advanced Binding Techniques
Custom Filters
Create reusable custom filters:
// Register custom filter
Canvelete.registerFilter('formatPhone', function(phone) {
return phone.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
});
// Use custom filter
"{{user.phone | formatPhone}}" // (555) 123-4567Computed Properties
Define calculated values:
// Computed properties configuration
{
"computed": {
"fullName": "{{user.firstName}} {{user.lastName}}",
"totalPrice": "{{quantity * unitPrice}}",
"discountAmount": "{{originalPrice - salePrice}}",
"isEligible": "{{user.age >= 18 && user.verified}}"
}
}
// Use computed properties
"Welcome, {{fullName}}!"
"Total: ${{totalPrice}}"Dynamic Data Loading
Load data based on user interactions:
// Dynamic data loading
{
"triggers": {
"onCategoryChange": {
"action": "loadData",
"dataSource": "products",
"parameters": {
"category": "{{selectedCategory}}"
}
}
}
}Real-Time Data Binding
WebSocket Connections
Connect to real-time data streams:
// WebSocket configuration
{
"dataSource": {
"type": "websocket",
"url": "wss://api.example.com/live-data",
"events": {
"priceUpdate": "updateProductPrice",
"stockChange": "updateInventory"
}
}
}Auto-Refresh
Automatically refresh data at intervals:
// Auto-refresh configuration
{
"dataSource": {
"type": "api",
"url": "https://api.example.com/dashboard",
"autoRefresh": {
"enabled": true,
"interval": 30000, // 30 seconds
"onError": "exponentialBackoff"
}
}
}Error Handling and Fallbacks
Graceful Degradation
Handle missing or invalid data:
// Default values
"{{user.name || 'Anonymous'}}"
"{{product.image || '/images/placeholder.jpg'}}"
// Type checking
"{{typeof price === 'number' ? price : 0}}"
// Safe navigation
"{{user?.profile?.bio || 'No bio available'}}"Error Boundaries
Define error handling strategies:
// Error handling configuration
{
"errorHandling": {
"onDataError": "showFallback",
"onBindingError": "logAndContinue",
"fallbackData": {
"user": {"name": "Guest User"},
"products": []
}
}
}Performance Optimization
Lazy Loading
Load data only when needed:
// Lazy loading configuration
{
"lazyLoad": {
"enabled": true,
"threshold": "50px", // Load when 50px from viewport
"placeholder": "Loading..."
}
}Data Caching
Cache frequently accessed data:
// Caching configuration
{
"cache": {
"enabled": true,
"ttl": 300000, // 5 minutes
"strategy": "lru", // Least Recently Used
"maxSize": 100 // Maximum cached items
}
}Batch Updates
Group multiple data updates:
// Batch update configuration
{
"batchUpdates": {
"enabled": true,
"debounce": 100, // Wait 100ms before applying updates
"maxBatchSize": 50
}
}Testing Data Binding
Mock Data
Use mock data for testing:
// Mock data configuration
{
"mockData": {
"enabled": true,
"scenarios": {
"emptyState": {"products": []},
"loadingState": {"loading": true},
"errorState": {"error": "Failed to load data"}
}
}
}Validation
Validate data binding setup:
// Validation rules
{
"validation": {
"required": ["user.name", "product.price"],
"types": {
"user.age": "number",
"user.email": "email",
"product.price": "currency"
}
}
}Best Practices
- Keep bindings simple: Avoid complex logic in templates
- Use computed properties: For calculated values
- Handle errors gracefully: Always provide fallbacks
- Optimize performance: Use caching and lazy loading
- Test thoroughly: With various data scenarios
- Document data structure: Make it clear what data is expected
Next Steps
- Explore Template Variables for advanced variable management
- Learn about Conditional Rendering for complex display logic
- Check out the API Reference for complete binding syntax