UNPKG

appblocks

Version:

A lightweight javascript library for building micro apps for the front-end.

580 lines (463 loc) • 14.6 kB
# Introduction ## Getting Started with AppBlocks AppBlocks is a tiny, fast, and lightweight JavaScript library for building micro applications. It's designed to be used primarily as a script tag to enhance web pages with self-contained micro applications. The goal of AppBlocks is to provide all the necessary ingredients to develop micro apps in websites while being ridiculously easy to integrate, practical, and small. > **New to AppBlocks?** Read about the [AppBlocks use case](whyappblocks.md) to understand when and why you might want to use it. ## Installation ### Option 1: CDN (Quickest) Add AppBlocks directly to your HTML: ```html <script src="https://cdn.jsdelivr.net/npm/appblocks@2.1.1/dist/appblocks.min.js"></script> ``` ### Option 2: NPM Install via npm for use with bundlers: ```bash npm install appblocks ``` Then import in your JavaScript: ```javascript import { AppBlock } from 'appblocks'; ``` ### Option 3: Direct Download Download the latest version and include it in your HTML: ```html <!-- Development version --> <script src="/path/to/appblocks.umd.js"></script> <!-- Minified production version --> <script src="/path/to/appblocks.min.js"></script> ``` ## Your First AppBlock Let's build a simple interactive app step by step. We'll start with an empty HTML page: ```html <!DOCTYPE html> <html lang="en"> <head> <title>My first AppBlocks app</title> </head> <body> <!-- Load AppBlocks. --> <script src="https://cdn.jsdelivr.net/npm/appblocks@2.1.1/dist/appblocks.min.js"></script> <script> // This is where we will write our AppBlock code </script> </body> </html> ``` ### Step 1: Create the Container and Template An AppBlock needs two elements: 1. **Container** - Where the app will render 2. **Template** - What the app will display Add these inside the `<body>`, before the script tags: ```html <!-- Container where our app will render --> <div id="app"></div> <!-- Template containing our app's markup --> <template id="appTemplate"> <h1>{data.message}</h1> <p>You've been here {data.visits} times.</p> <button id="increment-btn">Visit Again</button> </template> ``` > **Placeholders**: Notice the `{data.message}` and `{data.visits}` syntax? These are placeholders that will be replaced with actual data values. ### Step 2: Initialize Your AppBlock Add this JavaScript inside the `<script>` tag at the bottom: ```html <script> var app = new AppBlock({ el: document.getElementById('app'), template: document.getElementById('appTemplate'), data: { message: "Welcome to AppBlocks!", visits: 0 }, events: { 'click #increment-btn': function() { var currentVisits = this.Parent.data.visits; this.Parent.setData({ visits: currentVisits + 1 }); } } }); </script> ``` ### Step 3: See It in Action! Reload the page and click the button. Watch the visit count increase automatically! > **How it works**: When you call `setData()`, AppBlocks updates the data and automatically re-renders the interface to reflect the changes. ### Complete Example Here's the full working code: ```html <!DOCTYPE html> <html lang="en"> <head> <title>My First AppBlock</title> <style> body { font-family: Arial, sans-serif; padding: 20px; } #app { max-width: 400px; margin: 0 auto; } button { padding: 10px 20px; font-size: 16px; cursor: pointer; } </style> </head> <body> <div id="app"></div> <template id="appTemplate"> <h1>{data.message}</h1> <p>You've been here {data.visits} times.</p> <button id="increment-btn">Visit Again</button> </template> <script src="https://cdn.jsdelivr.net/npm/appblocks@2.1.1/dist/appblocks.min.js"></script> <script> var app = new AppBlock({ el: document.getElementById('app'), template: document.getElementById('appTemplate'), data: { message: "Welcome to AppBlocks!", visits: 0 }, events: { 'click #increment-btn': function() { var currentVisits = this.Parent.data.visits; this.Parent.setData({ visits: currentVisits + 1 }); } } }); </script> </body> </html> ``` ### Try It Yourself Open your browser's console and experiment: ```javascript // Update the message app.setData({ message: "Hello from the console!" }); // Reset the visits app.setData({ visits: 0 }); // Update multiple properties at once app.setData({ message: "AppBlocks is awesome!", visits: 100 }); ``` ## Next Steps Now that you have your first AppBlock running, explore these core concepts: - **[Data Management](data.md)** - Learn how to work with data effectively - **[Filters](filters.md)** - Transform data before displaying it - **[Directives](directives.md)** - Control element visibility with `if` conditionals and loops - **[Methods](methods.md)** - Organize your application logic - **[Event Handling](events.md)** - Respond to user interactions - **[HTTP Requests](requests.md)** - Fetch data from APIs ## Core Concepts Overview ### Filters - Transform Your Data Filters are functions that transform values before displaying them. They're perfect for formatting data without cluttering your templates. **Example: filters** ```js var app = new AppBlock({ el: document.getElementById('app'), template: document.getElementById('appTemplate'), data: { name: 'john doe', price: 49.99, tax: 23, rawText: ' hello world ' }, filters: { uppercase(self, value) { return value.toUpperCase(); }, afterTaxes(self, value) { return value + (value * self.data.tax / 100); }, currency(self, value) { return '$ ' + value.toFixed(2); } } }); ``` **Usage in templates:** ```html <template id="appTemplate"> <p>Welcome, {data.name|uppercase}!</p> <p>Total: {data.price|currency}</p> <!-- Chain multiple filters --> <p>With tax {data.tax}%: {data.price|afterTaxes|currency}</p> </template> ``` **Output:** ``` Welcome, JOHN DOE! Total: $ 49.99 With tax 23%: $ 61.49 ``` > Notice the `self` parameter on every filter. The first parameter in filters and methods is your app's instance. You can name it however you want, like `self`, `app` etc. AppBlocks will pass your app's instance to the first parameter automatically when you call a method or filter from the template and you can use it inside your method/filter to access data and methods from your app (just like in the `afterTaxes` filter). [šŸ“– Read more about Filters](filters.md#filters) ### Directives - Control Your Template Directives are special attributes that control element visibility and behavior. They make it easy to build dynamic interfaces. #### c-if & c-ifnot - Conditional Rendering Show or hide elements based on conditions: ```js var app = new AppBlock({ data: { isLoggedIn: false, age: 25, score: 85 } }); ``` ```html <template id="appTemplate"> <!-- Simple boolean check --> <p c-if="data.isLoggedIn">Welcome back!</p> <p c-ifnot="data.isLoggedIn">Please log in</p> <!-- Comparison operators --> <p c-if="data.age >= 18">You can vote</p> <p c-if="data.score > 60">You passed!</p> <!-- Complex expressions --> <p c-if="data.age >= 18 && data.score > 60">Congratulations, adult graduate!</p> </template> ``` [šŸ“– Read more about Conditional Rendering](directives.md#c-if) #### c-for - Loop Rendering Display lists and iterate over data: ```js var app = new AppBlock({ data: { users: [ { name: 'Alice', role: 'Admin' }, { name: 'Bob', role: 'User' }, { name: 'Charlie', role: 'User' } ], settings: { theme: 'dark', language: 'en', notifications: true } } }); ``` **Arrays:** ```html <ul> <li c-for="user in data.users"> {user.name} - {user.role} </li> </ul> ``` **Output:** ``` • Alice - Admin • Bob - User • Charlie - User ``` **Objects:** ```html <div c-for="key, value in data.settings"> <strong>{key}:</strong> {value} </div> ``` **Output:** ``` theme: dark language: en notifications: true ``` [šŸ“– Read more about Directives](directives.md) ### Event Handling - Respond to User Actions AppBlocks makes event handling clean and organized. Define all your event listeners in the `events` object: ```js var app = new AppBlock({ el: document.getElementById('app'), template: document.getElementById('appTemplate'), data: { count: 0, message: '' }, events: { 'click #increment': function(e, element) { this.Parent.setData({ count: this.Parent.data.count + 1 }); }, 'click #decrement': function(e, element) { this.Parent.setData({ count: this.Parent.data.count - 1 }); }, 'input #message-input': function(e, element) { this.Parent.setData({ message: element.value }); }, // Event delegation with complex selectors 'click .todo-list li .delete-btn': function(e, element) { // Handle delete button clicks on todo items } } }); ``` ```html <template id="appTemplate"> <div> <p>Count: {data.count}</p> <button id="increment">+</button> <button id="decrement">-</button> </div> <div> <input id="message-input" type="text" placeholder="Type something..." value="{data.message}"> <p>You typed: {data.message}</p> </div> </template> ``` **Event format:** `"eventName selector"` The selector can include spaces and use descendant combinators for complex element targeting. [šŸ“– Read more about Event Handling](api.md#events) ### Methods - Organize Your Logic Methods are where your application logic lives. They keep your code DRY (Don't Repeat Yourself) and reusable. ```js var app = new AppBlock({ el: document.getElementById('app'), template: document.getElementById('appTemplate'), data: { todos: [], newTodo: '' }, methods: { addTodo(self) { if (self.data.newTodo.trim()) { var updatedTodos = self.data.todos.concat({ id: Date.now(), text: self.data.newTodo, done: false }); self.setData({ todos: updatedTodos, newTodo: '' }); } }, removeTodo(self, id) { var updatedTodos = self.data.todos.filter(function(todo) { return todo.id !== id; }); self.setData({ todos: updatedTodos }); }, toggleTodo(self, id) { var updatedTodos = self.data.todos.map(function(todo) { if (todo.id === id) { return { ...todo, done: !todo.done }; } return todo; }); self.setData({ todos: updatedTodos }); } }, events: { 'click #add-btn': function() { this.Parent.methods.addTodo(this.Parent); }, 'input #new-todo-input': function(e, element) { this.Parent.setData({ newTodo: element.value }); }, 'click .remove-btn': function(e, element) { var id = parseInt(element.dataset.id); this.Parent.methods.removeTodo(this.Parent, id); } } }); ``` ```html <template id="appTemplate"> <input id="new-todo-input" type="text" placeholder="New todo" value="{data.newTodo}"> <button id="add-btn">Add Todo</button> <ul> <li c-for="todo in data.todos"> {todo.text} <button class="remove-btn" data-id="{todo.id}">Remove</button> </li> </ul> </template> ``` **Calling methods:** - From events: `this.Parent.methods.methodName(this.Parent, arg1, arg2)` - From directives (c-if, c-ifnot, c-for): `methodName(arg1, arg2)` (app instance auto-injected) - From placeholders: `{methodName(arg1, arg2)}` (app instance auto-injected) [šŸ“– Read more about Methods](methods.md#methods) ### HTTP Requests - Fetch Data from APIs AppBlocks provides built-in methods for making HTTP requests with automatic state management. You can use either `fetch` or Axios. #### Using fetchRequest ```js var app = new AppBlock({ el: document.getElementById('app'), template: document.getElementById('appTemplate'), data: { users: [], errorMessage: '' }, events: { 'click #load-users': function() { var app = this.Parent; app.fetchRequest( 'https://jsonplaceholder.typicode.com/users', { method: 'GET' }, { success: function(data) { app.setData({ users: data }); }, error: function(err) { app.setData({ errorMessage: err.message }); }, finally: function() { console.log('Request completed'); } } ); } } }); ``` #### Template with Loading States ```html <template id="appTemplate"> <button id="load-users">Load Users</button> <!-- Loading state --> <p c-if="isLoading()">Loading users...</p> <!-- Error state --> <div c-if="hasError()"> <p style="color: red;">Error: {data.errorMessage}</p> </div> <!-- Success state --> <div c-if="isSuccessful()"> <h2>Users ({data.users.length})</h2> <ul> <li c-for="user in data.users"> {user.name} - {user.email} </li> </ul> </div> </template> ``` **Built-in state methods:** - `isLoading()` - Returns `true` while request is in progress - `isSuccessful()` - Returns `true` when request succeeds - `hasError()` - Returns `true` when request fails [šŸ“– Read more about Requests](requests.md#http-requests) ## What's Next? You now have a solid understanding of AppBlocks basics! Here are some next steps: ### Deep Dive into Features - **[Data Management](data.md#data-management)** - Learn `setData()`, direct updates, and data patterns - **[Filters](filters.md#filters)** - Create custom filters and chain transformations - **[Directives](directives.md#directives)** - Master `c-if`, `c-for`, and custom directives - **[Methods](methods.md#methods)** - Build reusable application logic - **[HTTP Requests](requests.md#http-requests)** - Work with APIs using fetch and Axios - **[Utilities](utils.md#utilities)** - Helper functions for DOM manipulation - **[API Reference](api.md#api-reference)** - Complete API documentation ### Advanced Topics - Custom placeholder delimiters - Expression evaluation with built-ins - Render engine options (Idiomorph vs plain) - Custom directives and filters - Performance optimization ### Examples Check out practical examples and common patterns: - Todo List Application - Form Validation - Search with Debounce - Data Tables - Real-time Updates Happy coding with AppBlocks! šŸš€