You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/components.md
+63-4Lines changed: 63 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -78,12 +78,18 @@ OpenScript provides a declarative way to listen to events on elements.
78
78
79
79
When creating an element with `h`, you can pass a `listeners` object in the attributes.
80
80
81
+
> [!TIP]
82
+
> It is recommended to use **anonymous functions** for listeners to avoid potential memory leaks associated with direct binding. While OpenScript is generally memory-safe, using anonymous functions ensures that references are properly managed and collected.
83
+
81
84
```javascript
82
85
h.button(
83
86
{
84
87
class:"btn",
85
88
listeners: {
86
-
click:this.handleClick.bind(this),
89
+
// Preferred: Anonymous function
90
+
click: (e) =>this.handleClick(e),
91
+
92
+
// Also safe: Arrow functions defined inline
87
93
mouseover: (e) =>console.log("Hovered", e),
88
94
},
89
95
},
@@ -93,7 +99,7 @@ h.button(
93
99
94
100
### Method Binding
95
101
96
-
For class components, it's common to define methods for event handlers. Remember to `.bind(this)` or use arrow functions to preserve the correct `this` context.
102
+
While you can bind methods directly, be aware that creating new bound functions (e.g., `.bind(this)`) on every render can potentially lead to memory overhead if not handled correctly by the garbage collector.
If your component class defines methods starting with `$_`, OpenScript automatically treats them as event listeners for the component instance itself (lifecycle events).
128
+
OpenScript provides conventions for automatically listening to events based on method names.
129
+
130
+
#### Component Lifecycle & Emitted Events (`$_`)
131
+
132
+
Methods starting with `$_` are treated as listeners for events emitted by the component itself (including lifecycle events).
122
133
123
134
-`$_mounted()`: Called when the component is added to the DOM.
124
135
-`$_rendered()`: Called when the component is rendered.
136
+
-`$_customEvent()`: Listens for `this.emit('customEvent')`.
137
+
138
+
#### Broker Events (`$$`)
139
+
140
+
Methods starting with `$$` are treated as listeners for global events emitted via the **Broker**.
141
+
142
+
-`$$app_started()`: Listens for `app:started` event (dots/colons usually mapped to underscores).
143
+
-`$$user_login()`: Listens for `user:login` event.
144
+
145
+
```javascript
146
+
exportdefaultclassUserProfileextendsComponent {
147
+
// Listen to component's own mount event
148
+
$_mounted() {
149
+
console.log("UserProfile mounted");
150
+
}
151
+
152
+
// Listen to global 'auth:logout' event from Broker
153
+
$$auth_logout(user) {
154
+
console.log("User logged out:", user);
155
+
this.cleanUp();
156
+
}
157
+
}
158
+
```
159
+
160
+
### Inline Attribute Listeners
161
+
162
+
For inline event attributes (like `onclick`, `onchange`, etc.) that mimic standard HTML attributes, you can use `this.method('methodName', ...args)`. This approach allows you to reference component methods directly in the string attribute, which is useful when standard `listeners` object binding isn't applicable or preferred for specific attribute-based APIs.
163
+
164
+
```javascript
165
+
exportdefaultclassMyComponentextendsComponent {
166
+
greet(name) {
167
+
alert(`Hello, ${name}!`);
168
+
}
169
+
170
+
render() {
171
+
// Uses this.method to create a reference to the 'greet' method
172
+
// 'onclick' here is treated as an attribute, not a direct event listener attachment
_Note: `this.method()` is specifically for attributes that expect a string script (like `onclick` in HTML), bridging them back to your component's methods._
OpenScript Markup (OSM) is a powerful, JavaScript-based Domain Specific Language (DSL) for generating HTML. It uses the `h` object, a proxy that translates methods into HTML elements.
4
+
5
+
## Basic Syntax
6
+
7
+
To use OSM, you need to import the `app` instance and retrieve the `h` service.
8
+
9
+
```javascript
10
+
import { app } from"modular-openscriptjs";
11
+
12
+
consth=app("h");
13
+
14
+
// Simple element
15
+
constdiv=h.div("Hello World");
16
+
// Output: <div>Hello World</div>
17
+
```
18
+
19
+
### How it Works
20
+
21
+
The `h` object is a **Proxy**. When you access a property on it (e.g., `h.div`, `h.span`, `h.customElement`), it returns a function that generates an element with that tag name.
22
+
23
+
> **Note**: OSM supports all standard HTML tags (`h.section`, `h.a`, `h.img`) and custom elements (`h.myComponent`).
24
+
25
+
## Attributes & Properties
26
+
27
+
You can pass attributes as the first argument to the tag function if it is an object (and not a DOM node or State).
Copy file name to clipboardExpand all lines: docs/setting-up.md
+14Lines changed: 14 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -170,12 +170,26 @@ export function configureApp() {
170
170
* ---------------------------------------------
171
171
*/
172
172
app().value("appEvents", appEvents);
173
+
174
+
/**
175
+
* ---------------------------------------------
176
+
* Node Disposal Callback
177
+
* ---------------------------------------------
178
+
* Use this to clean up external library instances
179
+
* attached to DOM nodes when they are removed.
180
+
*/
181
+
registerNodeDisposalCallback((node) => {
182
+
// Example: Dispose Bootstrap tooltips/popovers
183
+
// if (node._bootstrap_tooltip) node._bootstrap_tooltip.dispose();
184
+
});
173
185
}
174
186
175
187
// execute configuration
176
188
configureApp();
177
189
```
178
190
191
+
> **Note**: `registerNodeDisposalCallback` is crucial for preventing memory leaks when using third-party libraries that attach instances to DOM elements (like Bootstrap, Tippy.js, etc.). The callback **MUST** be synchronous and stateless.
192
+
179
193
> **Note**: In the configuration above, we are using `appEvents` imported from `events.js`. We will cover the creation of `events.js` and how to handle events in the subsequent sections.
@@ -105,3 +111,24 @@ export function registerDomListeners(node, event, listener) {
105
111
listeners.add(listener);
106
112
eventMap.set(event,listeners);
107
113
}
114
+
115
+
/**
116
+
* used to safely remove a node from the DOM
117
+
* @param {Node} node
118
+
*/
119
+
exportfunctionremoveNode(node){
120
+
destroyNodeDeep(node);
121
+
node.remove();
122
+
}
123
+
124
+
/**
125
+
* used to register a callback that will be called when a node is removed from the DOM. Use this to clean up the node to avoid memory leaks. e.g. Remove Bootstrap components attached to the node.
0 commit comments