Advanced Functionalities

Reactive Loops with <foreachof>

The <foreachof> tag creates reactive loops that dynamically update the DOM when the underlying data changes.

Syntax:

<foreachof a.jsvariable="value, index">
  {(<div>${...}</div>)}
</foreachof>

Example:

<a-closure>
  <let>
    global watched g.items = ["Item 1", "Item 2", "Item 3"];
  </let>
  <foreachof a.jsvariable="g.items, idx">
    {(<div key="${idx}">${g.items[idx]}</div>)}
  </foreachof>
</a-closure>

Custom Tags and Elements attributes

singleton

Description:

The singleton attribute ensures only one instance of an element with the same singleton name exists. Any new element with the same name will be automatically removed from the DOM before a.js does any parsing/execution.

Behavior:
Syntax:
<a-closure singleton="unique-component">
  <div>Unique Content</div>
</a-closure>

singletonreplace

Description:

The singletonreplace attribute allows replacing existing singletons.

Behavior:
Syntax:
<a-closure singleton="unique-component" singletonreplace>
  <div>Replaced Content</div>
</a-closure>

waitFor

Description:

The waitFor attribute delays the parsing and execution of an element until specified conditions are met. It uses a chain of selectors to resolve dependencies.

Behavior:
Syntax:
<a-closure waitFor='["my-layout", "#main", "my-page"]'>
  <div>Dependent Content</div>
</a-closure>
Example:

Modular Imports in a.js

Overview

The <import> tag in a.js allows developers to dynamically include external JavaScript, CSS, or HTML resources into their projects, but it must be used within <a-xxxxx> elements. This ensures that imports are scoped to the containing custom element, preventing unintended side effects on unrelated parts of the application.

Key Features

  1. Recursive Import Resolution: Handles dependencies between imported modules.
  2. Scoped Resource Application: Automatically scoped by the enclosing <a-xxxxx> element.
  3. Dynamic Resource Loading: Allows runtime inclusion of resources using the A.importIn function.
  4. Pre-parsing Behavior: Imports are processed before any other content in the enclosing <a-xxxxx> element, influencing the final structure and behavior of the element.

Syntax

The <import> tag uses the following attributes:

Example

<a-closure>
  <import src="./styles/main.css" type="css"></import> //import the styles in main.css in a way that only applies them to the children of currentElement
  <import src="./scripts/utils.js" type="javascript"></import> //replace this <import></import> tag by the text of the ./scripts/utils.js file. If this text contains an import tag, it will be resolved too.
  <import src="./components/header.html" type="html"></import> //import the content of ./components/header.html as child nodes of currentElement.
</a-closure>

Detailed Behavior

Pre-parsing Behavior

Imports are the first elements to be processed inside an <a-xxxxx> element. This means that they are parsed and executed before any other content or logic within the element. This means it (usually) makes no sense to write something like

<a-closure>
  currentElement.innerHTML = '<import src="./styles/dark-theme.css" type="css"></import>';
</a-closure>

Because at runtime, the <import> will have been processed, and the script inside <a-closure> will see the following:

<a-closure>
  currentElement.innerHTML = '';
</a-closure>

Recursive Import Resolution

When an imported resource references additional dependencies, a.js resolves these recursively. This ensures that all necessary resources are loaded before the application interacts with them.

Example

If utils.js contains <import src="./scripts/helpers.js"></import>, the following code ensures both are loaded:

<a-closure>
  <import src="./scripts/utils.js" type="javascript"></import>
</a-closure>

Dynamic Resource Loading

Dynamic resource loading can be accomplished using A.importIn, which programmatically loads resources into a specified element.

Example

A.importIn(currentElement, './html/layout.html', "html");

Practical Use Cases

Modular Component Development

By importing HTML fragments as custom components, developers can keep their code modular and reusable.

Example

<a-tagDef forTag="custom-card">
  <import src="./components/card.tagdef"></import>
</a-tagDef>

<custom-card></custom-card>

Dynamic Style Application

Switching themes or applying styles dynamically based on user actions is simplified with A.importIn.

Example


<a-closure>
  {(<button onclick="loadTheme('dark')">Dark Theme</button>)}
  {(<button onclick="loadTheme('light')">Light Theme</button>)}
  let loaded = null;
  function loadTheme(theme) {
      if (loaded) {
        loaded.obj.remove();
    }
    A.importIn(currentElement, `./styles/${theme}-theme.css`, 'css',(elem,url,type,imports) => {
        loaded = imports.css[0]
    },true });
  }
</a-closure>

Best Practices

  1. Minimize Overuse: Avoid overloading the application with too many <import> tags to maintain performance.
  2. Understand Pre-parsing: Remember that imports are processed before any other logic in the enclosing <a-xxxxx> element.
  3. Lazy Loading: Utilize A.importIn to load resources dynamically and optimize page load times.

By using the <import> tag effectively, developers can create highly modular, dynamic, and maintainable web applications with a.js.


> Reactive state management