Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,39 @@
If the body always needs to reference the same element regardless of how the function is called, pass it as a capture instead of relying on `this`.


[[add-js-initializer]]
== Client-Side Lifecycle With `addJsInitializer` [since:com.vaadin:vaadin@V25.2]

Check failure on line 245 in articles/flow/component-internals/element-api/calling-javascript.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Terms] Use '(?-i)Vaadin' instead of 'vaadin'. Raw Output: {"message": "[Vale.Terms] Use '(?-i)Vaadin' instead of 'vaadin'.", "location": {"path": "articles/flow/component-internals/element-api/calling-javascript.adoc", "range": {"start": {"line": 245, "column": 61}}}, "severity": "ERROR"}

The [methodname]`Element.addJsInitializer()` method registers a JavaScript expression that runs each time a client-side DOM node is created for the element, and whose returned cleanup callback runs when that DOM node is discarded or the returned [classname]`Registration` is removed.

Use this when you need to install something on the client-side DOM – an event listener, a third-party widget, an observer – and reliably tear it down. A one-shot [methodname]`executeJs()` call doesn't cover two cases: a real re-attach gives the element a brand-new DOM node that no longer has your listener, and cleanup from a server-side detach listener cannot be delivered because the element is leaving the tree.

The expression syntax is the same as [methodname]`executeJs()`: `this` is the host element on the client, and parameters are referenced as `$0`, `$1`, …. If the expression returns a function, that function is invoked at teardown.

Check failure on line 251 in articles/flow/component-internals/element-api/calling-javascript.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'teardown'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'teardown'?", "location": {"path": "articles/flow/component-internals/element-api/calling-javascript.adoc", "range": {"start": {"line": 251, "column": 228}}}, "severity": "ERROR"}

.Installing a listener with cleanup
[example]
====
[source,java]
----
Registration registration = getElement().addJsInitializer("""
const handler = (event) => console.log('clicked', event.target);
this.addEventListener('click', handler);
return () => this.removeEventListener('click', handler);
""");
----
====

Remove the registration on the server when the listener is no longer needed; the cleanup callback then runs on the client.


=== Re-Attach Semantics

The initializer is re-run after a real re-attach – when the element is removed from the DOM in one round trip and re-added in a later one, and so the browser receives a fresh DOM node. It is *not* re-run when the element is detached and re-attached on the server inside a single round trip, because the client never discarded its DOM in that case.

Check failure on line 271 in articles/flow/component-internals/element-api/calling-javascript.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'initializer'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'initializer'?", "location": {"path": "articles/flow/component-internals/element-api/calling-javascript.adoc", "range": {"start": {"line": 271, "column": 5}}}, "severity": "ERROR"}


=== Cleanup Constraints

The return value of the expression is read synchronously. A function is treated as the cleanup callback; returning nothing (no `return`, or `undefined`) means there's no cleanup. Returning any other value – including a `Promise` resolving to a function – is logged as an error on the client. If you need asynchronous setup, do the async work inside the body and store the teardown in a synchronously returned function.

Check failure on line 276 in articles/flow/component-internals/element-api/calling-javascript.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'teardown'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'teardown'?", "location": {"path": "articles/flow/component-internals/element-api/calling-javascript.adoc", "range": {"start": {"line": 276, "column": 385}}}, "severity": "ERROR"}


[discussion-id]`AB7EDF45-DB22-4560-AF27-FF1DC6944482`
Loading