For state-less components we can use functions as UI components (see “Elements” page). But in real life, we may need to handle the component live-cycle and provide JavaScript the way to properly use the Garbage collection.
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
-import { scope, el, on } from "deka-dom-el";
+import { scope, el } from "deka-dom-el";
/** @type {ddeElementAddon} */
The library therefore use scopes to provide these functionalities.
The host is the name for the element representing the component. This is typically element returned by function. To get reference, you can use scope.host() to applly addons just use scope.host(...<addons>).
import { el, on, scope } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
const { host }= scope;
@@ -34,7 +34,7 @@ function component(){
el("strong", "Component")
);
}
-
To better understanding we implement function elClass helping to create component as class instances.
import { chainableAppend, el, scope } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
+
To better understanding we implement function elClass helping to create component as class instances.
As you can see, the scope.host() is stored temporarily and synchronously. Therefore, at least in the beginning of using library, it is the good practise to store host in the root of your component. As it may be changed, typically when there is asynchronous code in the component.
import { el, scope, on, dispatchEvent } from "deka-dom-el";
+document.body.append(
+ el(component)
+);
+function component(){
+ const { host }= scope; // good practise!
+
+ host(
+ console.log,
+ on("click", function redispatch(){
+ // this `host` ↘ still corresponds to the host ↖ of the component
+ dispatchEvent("redispatch")(host());
+ })
+ );
+ // this `host` ↘ still corresponds to the host ↖ of the component
+ setTimeout(()=> dispatchEvent("timeout")(host()), 750)
+ return el("p", "Clickable paragraph!");
+}
+
The host is internally used to register the cleaning procedure, when the component (host element) is removed from the DOM.
import { el, empty } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
+document.body.append(
+ el(component),
+ el("button", {
+ textContent: "Remove",
+ onclick: ()=> empty(document.body),
+ type: "button"
+ })
+);
+import { on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
+import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
+function component(){
+ const textContent= O("Click to change text.");
+
+ const onclickChange= on("click", function redispatch(){
+ textContent("Text changed! "+(new Date()).toString())
+ });
+ return el("p", textContent, onclickChange);
+}
+
The text content of the paragraph is changing when the value of the observable textContent is changed. Internally, there is association between textContent and the paragraph similar to using S.on(textContent, /* update the paragraph */).
This listener must be removed when the component is removed from the DOM. To do it, the library assign internally on.disconnect(/* remove the listener */)(host()) to the host element.
The library DOM API and observables works ideally when used declaratively. It means, you split your app logic into three parts as it was itroduced in Observables.
Strictly speaking, the imperative way of using the library is not prohibited. Just be careful (rather avoid) mixing declarative approach (using observables) and imperative manipulation of elements.
/* PSEUDO-CODE!!! */
+import { el, on, scope } from "deka-dom-el";
+function component(){
+ const ul= el("ul");
+ const ac= new AbortController();
+ fetchAPI({ signal: ac.signal }).then(data=> {
+ data.forEach(d=> ul.append(el("li", d)));
+ });
+ scope.host(
+ /* element was remove before data fetched */
+ on.disconnected(()=> ac.abort())
+ );
+ return ul;
+ /**
+ * NEVER EVER!!
+ * let data;
+ * fetchAPI().then(d=> data= O(d));
+ *
+ * OR NEVER EVER!!
+ * const ul= el("ul");
+ * fetchAPI().then(d=> {
+ * const data= O("data");
+ * ul.append(el("li", data));
+ * });
+ *
+ * // THE HOST IS PROBABLY DIFFERENT THAN
+ * // YOU EXPECT AND OBSERVABLES MAY BE
+ * // UNEXPECTEDLY REMOVED!!!
+ * */
+}
+