UNPKG

node-red-contrib-uibuilder

Version:

Easily create data-driven web UI's for Node-RED. Single- & Multi-page. Multiple UI's. Work with existing web development workflows or mix and match with no-code/low-code features.

126 lines (100 loc) 4.11 kB
--- title: Reactive - A class to create reactive variables description: | The `Reactive` class enables the creation and management of reactive variables. created: 2025-06-14 16:21:29 updated: 2026-03-18 13:31:57 --- ## Potential Limitations OnChange callback `target` parameter only shows the CURRENT level. Changing a deeply nested property will return the containing object/array and not the full source object. This is a limitation of the current implementation and may be addressed in future updates. Similarly, deleting a property may result in an "empty item" being returned. If the target is a JS native object (like `Date`, `Map`, `Set`, etc.), simply assigning to the proxied object will destroy the proxy. You have to use the `value` property to update the value of the proxy. ### 1. **Reactive Class** ```javascript // Class methods are not directly accessible from the uibuilder reactive() function. export class Reactive { constructor(srcvar, eventDispatcher) create() // Creates and returns the reactive proxy getListenerCount() // Returns number of active listeners clearAllListeners() // Clears all listeners // Private methods: _isReactive(obj) _triggerListeners(propertyPath, value, oldValue, target) _createReactiveObject(obj, basePath = '') } ``` ### 2. **Simple use** ```javascript // From the uibuilder client library: const data = uibuilder.reactive({ count: 0 }) // Class-based approach: const ReactiveClass = uibuilder.getReactiveClass() const reactiveInstance = new ReactiveClass({ count: 0 }, customEventDispatcher) const proxy = reactiveInstance.create() ``` ### 3. **Enhanced Encapsulation** - All state (listeners, counter, target) is now properly encapsulated in the class - Methods are clearly separated into public and private - Better organization with proper class structure ## Benefits of the Class Approach: ### **1. Better State Management** ```javascript const reactive1 = new Reactive(data1) const reactive2 = new Reactive(data2) // Each instance has its own isolated state console.log(reactive1.getListenerCount()) // Independent listener counts ``` ### **2. Enhanced Control** ```javascript const reactiveInstance = new Reactive(data) const proxy = reactiveInstance.create() // Add listeners const ref1 = proxy.onChange(callback1) const ref2 = proxy.onChange(callback2) // Monitor listener count console.log(reactiveInstance.getListenerCount()) // 2 // Clear all listeners at once reactiveInstance.clearAllListeners() console.log(reactiveInstance.getListenerCount()) // 0 ``` ### **3. Multiple Reactive Objects** ```javascript // Create multiple reactive instances with different configurations const userReactive = new Reactive(userData, userEventDispatcher) const appReactive = new Reactive(appData, appEventDispatcher) const userProxy = userReactive.create() const appProxy = appReactive.create() ``` ### **4. Advanced Usage** ```javascript // Direct class usage for advanced scenarios const ReactiveClass = uibuilder.getReactiveClass() const customReactive = new ReactiveClass(data, (eventType, details) => { // Custom event handling console.log(`Custom event: ${eventType}`, details) }) ``` ## Key Features: 1. **Full Property Path Tracking**: Provides complete paths like `"user.profile.name"` 2. **Deep Reactivity**: Nested objects automatically become reactive 3. **Event Dispatching**: Custom events are dispatched 4. **Change Listeners**: `onChange` and `cancelChange` ## Usage Examples: ### **Simple Usage** ```javascript const data = uibuilder.reactive({ count: 0 }) const ref = data.onChange((newVal, oldVal, path) => { console.log(`${path}: ${oldVal} → ${newVal}`) }) ``` ### **Advanced Class Usage** ```javascript const ReactiveClass = uibuilder.getReactiveClass() const instance = new ReactiveClass({ count: 0 }) const proxy = instance.create() // Monitor and manage listeners console.log(instance.getListenerCount()) // 0 const ref = proxy.onChange(callback) console.log(instance.getListenerCount()) // 1 instance.clearAllListeners() ```