mirror of
https://github.com/jaandrle/deka-dom-el
synced 2024-11-22 16:55:23 +01:00
💥 on.(dis)connected
only once
This commit is contained in:
parent
51ccd11f82
commit
cd6ba98469
48
dist/dde-with-observables.js
vendored
48
dist/dde-with-observables.js
vendored
File diff suppressed because one or more lines are too long
40
dist/dde.js
vendored
40
dist/dde.js
vendored
File diff suppressed because one or more lines are too long
8
dist/esm-with-observables.js
vendored
8
dist/esm-with-observables.js
vendored
File diff suppressed because one or more lines are too long
2
dist/esm.js
vendored
2
dist/esm.js
vendored
File diff suppressed because one or more lines are too long
@ -67,7 +67,7 @@ document.body.append(
|
|||||||
function log({ type, detail }){
|
function log({ type, detail }){
|
||||||
console.log({ _this: this, type, detail });
|
console.log({ _this: this, type, detail });
|
||||||
}
|
}
|
||||||
</code></div><script>Flems(document.getElementById("code-example-1-35hjjp3e4js"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst paragraph= el(\\\"p\\\", \\\"See live-cycle events in console.\\\",\\n\\tel=> log({ type: \\\"dde:created\\\", detail: el }),\\n\\ton.connected(log),\\n\\ton.disconnected(log),\\n\\ton.attributeChanged(log));\\n\\ndocument.body.append(\\n\\tparagraph,\\n\\tel(\\\"button\\\", \\\"Update attribute\\\", on(\\\"click\\\", ()=> paragraph.setAttribute(\\\"test\\\", Math.random().toString()))),\\n\\t\\\" \\\",\\n\\tel(\\\"button\\\", \\\"Remove\\\", on(\\\"click\\\", ()=> paragraph.remove()))\\n);\\n\\n/** @param {Partial<CustomEvent>} event */\\nfunction log({ type, detail }){\\n\\tconsole.log({ _this: this, type, detail });\\n}\\n\"}],\"toolbar\":false}"));</script><p>For Custom elements, we will later introduce a way to replace <code>*Callback</code> syntax with <code>dde:*</code> events. The <code>on.*</code> functions then listen to the appropriate Custom Elements events (see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks">Custom element lifecycle callbacks | MDN</a>).</p><p>But, in case of regular elemnets the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"><code>MutationObserver</code> | MDN</a> is internaly used to track these events. Therefore, there are some drawbacks:</p><ul><li>To proper listener registration, you need to use <code>on.*</code> not `on("dde:*", …)`!</li><li>Use sparingly! Internally, library must loop of all registered events and fires event properly. <strong>It is good practice to use the fact that if an element is removed, its children are also removed!</strong> In this spirit, we will introduce later the <strong>host</strong> syntax to register clean up procedures when the component is removed from the app.</li></ul><h3 id="h-final-notes"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-final-notes" tabindex="-1">#</a> Final notes</h3><p>The library also provides a method to dispatch the events.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-2-b6a1hbrxh7s" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on, dispatchEvent } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
|
</code></div><script>Flems(document.getElementById("code-example-1-35hjjp3e4js"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js\\\";\\nconst paragraph= el(\\\"p\\\", \\\"See live-cycle events in console.\\\",\\n\\tel=> log({ type: \\\"dde:created\\\", detail: el }),\\n\\ton.connected(log),\\n\\ton.disconnected(log),\\n\\ton.attributeChanged(log));\\n\\ndocument.body.append(\\n\\tparagraph,\\n\\tel(\\\"button\\\", \\\"Update attribute\\\", on(\\\"click\\\", ()=> paragraph.setAttribute(\\\"test\\\", Math.random().toString()))),\\n\\t\\\" \\\",\\n\\tel(\\\"button\\\", \\\"Remove\\\", on(\\\"click\\\", ()=> paragraph.remove()))\\n);\\n\\n/** @param {Partial<CustomEvent>} event */\\nfunction log({ type, detail }){\\n\\tconsole.log({ _this: this, type, detail });\\n}\\n\"}],\"toolbar\":false}"));</script><p>For Custom elements, we will later introduce a way to replace <code>*Callback</code> syntax with <code>dde:*</code> events. The <code>on.*</code> functions then listen to the appropriate Custom Elements events (see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks">Custom element lifecycle callbacks | MDN</a>).</p><p>But, in case of regular elemnets the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"><code>MutationObserver</code> | MDN</a> is internaly used to track these events. Therefore, there are some drawbacks:</p><ul><li>To proper listener registration, you need to use <code>on.*</code> not `on("dde:*", …)`!</li><li>Use sparingly! Internally, library must loop of all registered events and fires event properly. <strong>It is good practice to use the fact that if an element is removed, its children are also removed!</strong> In this spirit, we will introduce later the <strong>host</strong> syntax to register clean up procedures when the component is removed from the app.</li></ul><p>To provide intuitive behaviour, similar also to how the life-cycle events works in other frameworks/libraries, deka-dom-el library ensures that <code>on.connected</code> and <code>on.disconnected</code> are called only once and only when the element is (dis)connected to live DOM. The solution is inspired by <a href="https://vuejs.org/guide/extras/web-components.html#lifecycle" title="Vue and Web Components | Lifecycle">Vue</a>. For using native behaviour re-(dis)connecting element, use:</p><ul><li>custom <code>MutationObserver</code> or logic in (dis)<div class="code"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js"></code></div> or…</li><li>re-add <code>on.connected</code> or <code>on.disconnected</code> listeners.</li></ul><h3 id="h-final-notes"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-final-notes" tabindex="-1">#</a> Final notes</h3><p>The library also provides a method to dispatch the events.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-2-b6a1hbrxh7s" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on, dispatchEvent } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";
|
||||||
document.body.append(
|
document.body.append(
|
||||||
el("p", "Listenning to `test` event.", on("test", console.log)).append(
|
el("p", "Listenning to `test` event.", on("test", console.log)).append(
|
||||||
el("br"),
|
el("br"),
|
||||||
|
@ -108,6 +108,17 @@ export function page({ pkg, info }){
|
|||||||
" clean up procedures when the component is removed from the app."
|
" clean up procedures when the component is removed from the app."
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
el("p").append(
|
||||||
|
"To provide intuitive behaviour, similar also to how the life-cycle events works in other",
|
||||||
|
" frameworks/libraries, deka-dom-el library ensures that ", el("code", "on.connected"),
|
||||||
|
" and ", el("code", "on.disconnected"), " are called only once and only when the element",
|
||||||
|
" is (dis)connected to live DOM. The solution is inspired by ", el("a", { textContent: "Vue", href: "https://vuejs.org/guide/extras/web-components.html#lifecycle", title: "Vue and Web Components | Lifecycle" }), ".",
|
||||||
|
" For using native behaviour re-(dis)connecting element, use:"
|
||||||
|
),
|
||||||
|
el("ul").append(
|
||||||
|
el("li").append("custom ", el("code", "MutationObserver"), " or logic in (dis)", el(code, "connectedCallback"), " or…"),
|
||||||
|
el("li").append("re-add ", el("code", "on.connected"), " or ", el("code", "on.disconnected"), " listeners.")
|
||||||
|
),
|
||||||
|
|
||||||
el(h3, "Final notes"),
|
el(h3, "Final notes"),
|
||||||
el("p", "The library also provides a method to dispatch the events."),
|
el("p", "The library also provides a method to dispatch the events."),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { keyDM, keyLTE } from "./dom-common.js";
|
import { keyLTE } from "./dom-common.js";
|
||||||
import { scope } from "./dom.js";
|
import { scope } from "./dom.js";
|
||||||
export function customElementRender(custom_element, render, props= observedAttributes){
|
export function customElementRender(custom_element, render, props= observedAttributes){
|
||||||
scope.push({
|
scope.push({
|
||||||
@ -16,14 +16,11 @@ export function lifecycleToEvents(class_declaration){
|
|||||||
target.apply(thisArg, detail);
|
target.apply(thisArg, detail);
|
||||||
thisArg.dispatchEvent(new Event("dde:connected"));
|
thisArg.dispatchEvent(new Event("dde:connected"));
|
||||||
});
|
});
|
||||||
if(!class_declaration.prototype[keyDM])
|
|
||||||
class_declaration.prototype[keyDM]= "dde";
|
|
||||||
wrapMethod(class_declaration.prototype, "disconnectedCallback", function(target, thisArg, detail){
|
wrapMethod(class_declaration.prototype, "disconnectedCallback", function(target, thisArg, detail){
|
||||||
target.apply(thisArg, detail);
|
target.apply(thisArg, detail);
|
||||||
const dispatch= ()=> thisArg.dispatchEvent(new Event("dde:disconnected"));
|
(queueMicrotask || setTimeout)(
|
||||||
if(thisArg[keyDM]!=="dde")
|
()=> !thisArg.isConnected && thisArg.dispatchEvent(new Event("dde:disconnected"))
|
||||||
return dispatch();
|
);
|
||||||
(queueMicrotask || setTimeout)(()=> !thisArg.isConnected && dispatch());
|
|
||||||
});
|
});
|
||||||
wrapMethod(class_declaration.prototype, "attributeChangedCallback", function(target, thisArg, detail){
|
wrapMethod(class_declaration.prototype, "attributeChangedCallback", function(target, thisArg, detail){
|
||||||
const [ attribute, , value ]= detail;
|
const [ attribute, , value ]= detail;
|
||||||
|
@ -27,4 +27,3 @@ function setDeleteAttr(obj, prop, val){
|
|||||||
return Reflect.set(obj, prop, "");
|
return Reflect.set(obj, prop, "");
|
||||||
}
|
}
|
||||||
export const keyLTE= "__dde_lifecycleToEvents"; //boolean
|
export const keyLTE= "__dde_lifecycleToEvents"; //boolean
|
||||||
export const keyDM= "__dde_disconnect_mode"; //native (unset) | dde | skip
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export { registerReactivity } from './observables-common.js';
|
export { registerReactivity } from './observables-common.js';
|
||||||
import { enviroment as env, keyDM, keyLTE } from './dom-common.js';
|
import { enviroment as env, keyLTE } from './dom-common.js';
|
||||||
|
|
||||||
export function dispatchEvent(name, options, host){
|
export function dispatchEvent(name, options, host){
|
||||||
if(!options) options= {};
|
if(!options) options= {};
|
||||||
@ -32,8 +32,7 @@ on.connected= function(listener, options){
|
|||||||
const name= "connected";
|
const name= "connected";
|
||||||
if(typeof options !== "object")
|
if(typeof options !== "object")
|
||||||
options= {};
|
options= {};
|
||||||
if(typeof options.once !== "boolean")
|
options.once= true;
|
||||||
options.once= true;
|
|
||||||
return function registerElement(element){
|
return function registerElement(element){
|
||||||
if(custom_element) element= custom_element;
|
if(custom_element) element= custom_element;
|
||||||
const event= "dde:"+name;
|
const event= "dde:"+name;
|
||||||
@ -51,11 +50,9 @@ on.disconnected= function(listener, options){
|
|||||||
const name= "disconnected";
|
const name= "disconnected";
|
||||||
if(typeof options !== "object")
|
if(typeof options !== "object")
|
||||||
options= {};
|
options= {};
|
||||||
if(typeof options.once !== "boolean")
|
options.once= true;
|
||||||
options.once= true;
|
|
||||||
return function registerElement(element){
|
return function registerElement(element){
|
||||||
if(custom_element) element= custom_element;
|
if(custom_element) element= custom_element;
|
||||||
if(!element[keyDM]) element[keyDM]= "dde";
|
|
||||||
const event= "dde:"+name;
|
const event= "dde:"+name;
|
||||||
element.addEventListener(event, listener, options);
|
element.addEventListener(event, listener, options);
|
||||||
if(element[keyLTE]) return element;
|
if(element[keyLTE]) return element;
|
||||||
@ -212,11 +209,7 @@ function connectionsChangesObserverConstructor(){
|
|||||||
|
|
||||||
const ls= store.get(element);
|
const ls= store.get(element);
|
||||||
if(!ls.length_d) continue;
|
if(!ls.length_d) continue;
|
||||||
const dispatch= dispatchRemove(element);
|
(queueMicrotask || setTimeout)(dispatchRemove(element));
|
||||||
if(element[keyDM]==="dde")
|
|
||||||
(queueMicrotask || setTimeout)(dispatch);
|
|
||||||
else
|
|
||||||
dispatch();
|
|
||||||
out= true;
|
out= true;
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
Loading…
Reference in New Issue
Block a user