Directives in AgnosUI are inspired by the actions in Svelte. These directives are element-level lifecycle functions that are executed when the element is created. They are updated (if an update function is provided) when a parameter changes, and finally, they are executed when the element is destroyed. These directives are typically used to add custom event handlers. For instance, core services like focus track and floating ui create directives that are utilized by components such as Select.
The usage of this function is dependent on the JavaScript framework (if any) that the application utilizes. For instance, in this guide, we are using simple TypeScript without any specific framework.
A directive is a function that takes as input an HTMLElement
and an optional parameter, for example an object representing a configuration.
This function will execute a first time when the directive is applied to an element (usually when the DOM element is created) and either it returns void
, or 2 optional functions:
update
function, called when the context changed and you need either to update the directive configuration or to re-execute partially the original function or modify some internal state of the directive.destroy
function, used to remove eventual listeners, subscriptions or any reactive objects created by the directive. This function is usually called when the DOM element on which you applied the directive gets removed from the DOM.This example shows a very simple directive that creates an event listener on click
events that happen on the HTML element and then print the parameter text
in the console, along with the clicked target.
Both update
and destroy
functions are provided by the directive, as following:
update
: gives a way to modify the original text to something new, when the context changes (see in the next section).destroy
: remove the previously created listener, so that you don't bloat the main thread with unused listeners.Considering this HTML page, in which you have a div
container focus-element
that includes 2 button
, an input text clickText
and another button
that removes the container.
To use the directive in vanilla TS you need the following steps:
focus-element
container.button 1
, the listener triggers clickListener
function and you get a log into the console:button 2
, since it also belongs to the element focus-element
on which we applied the directive.Changing the input does not change anything, because the update
function has no bindings and it is never called. To solve it, we need the next step.
update
function accordingly. For example, we want to change the text to the value of the clickText
input when it changes.update
function to a change event on the input clickText
.
Type Update has been called!
in the input and then click again on button 1
, you get:focus-element
gets remove from the DOM. This can be done for example using a MutationObserver
on the parent DOM element.remove dom element
, that remove completely the focus-element
container from the DOM. Last log will be printed:Directives are traditionnally run only on the browser. However, you may want to create a directive that updates attributes / class / style of an element. In those cases, being compatible with the framework server-side rendering capabilities is important to avoid any flickering.
In that context, AgnosUI provides the following utilities:
browserDirective
wraps a browser-only directive to make sure it is not run on the server.createAttributesDirective
is a simple directive factory that allows users to update attributes / class / style and bind events. The resulting directive can be run on the server.As seen in the previous section, a Directive
is framework agnostic. But the way frameworks expose the DOM element and binds life-cycle events can be very different. Frameworks controls life-cycle events of the DOM elements, in particular initialization, updates and destroy.
The headless libraries of AgnosUI contain adapters to bind directives in the correct way, so that the corresponding events are called at the right moment benefiting from framework features.
In React, DOM nodes are accessed via Refs
. Agnos takes advantage of RefCallback
to assign an Agnos Directive
to a DOM element, and use the ref.current
to initialize the directive, update and destroy it.
It is done by using the custom hook useDirective
, that takes as parameters the directive itself and an optional configuration.
It returns the React ref
and potentially other attributes. Those other attributes only matter / are used when Server-Side Rendering is enabled.
Note that useDirective
, as a React hook, holds the same constraints as regular React hooks (for instance cannot be inside a loop or conditional block).
Agnos has a utility mergeDirectives
to merge directives into one, with a limitation on the argument:
all directives receive the same argument upon initialization and update.
Directives are created and updated in the same order as they appear in the arguments list,
they are destroyed in the reverse order.
All calls to the directives (to create, update and destroy them) are wrapped in a call to the batch function of tansu
Note that it is not mandatory to use mergeDirectives
to use multiple directives on the same element as frameworks support using multiple directives on the same element.