Targets
Targets let you reference important elements by name.
<div data-module="search">
<input type="text" data-el="search.query">
<div data-el="search.errorMessage"></div>
<div data-el="search.results"></div>
</div>
Attributes and Names
The data-el attribute is called a target attribute, and its value is a space-separated list of target names which you can use to refer to the element in the search module.
<div data-module="search">
<div data-el="search.results"></div>
</div>
Definitions
Define target names in your module class using the static targets array:
// modules/search.js
import { Module } from '@by-association-only/theme-module'
export default class extends Module {
static targets = ['query', 'errorMessage', 'results']
// …
}
Properties
For each target name defined in the static targets array, the module system adds the following properties to your module, where [name] corresponds to the target’s name:
| Kind | Name | Value |
|---|---|---|
| Singular | this.[name]El | This first matching element in scope |
| Plural | this.[name]Els | An array of all the matching elements in scope |
| Existential | this.has[Name]El | A boolean indicating whether there is a matching element in scope |
Note: Accessing the singular target property will throw an error when there is no matching element.
Selectors
A #selectors property gets added to the module everytime the targets array is used. It is an object that allows you
// modules/search.js
import { Module } from '@by-association-only/theme-module'
export default class extends Module {
static targets = ['query', 'errorMessage', 'results']
get selectors () {
return {
query: '[data-el*="search.query"]',
errorMessage: '[data-el*="search.errorMessage"]',
results: '[data-el*="search.results"]',
}
}
}
A good example usage of this is checking for existance of an element in an event
// modules/search.js
import { Module } from '@by-association-only/theme-module'
export default class extends Module {
static methods = ['onBodyClick']
static targets = ['query', 'errorMessage', 'results']
setupListeners () {
this.listeners.add(document.body, 'click', this.onBodyClick)
}
async onBodyClick (e) {
if (e.target.closest(this.selectors.errorMessage) == null) return
// …
}
}
External targets
External targets work very much in the same way as regular targets. This just grabs element that are inside and outside of scope.
<body>
<header data-external-el="search.header">
<h1>By Association Only</h1>
</header>
<div data-module="search">
<input type="text" data-el="search.query">
<div data-el="search.errorMessage"></div>
<div data-el="search.results"></div>
</div>
</body>
// modules/search.js
import { Module } from '@by-association-only/theme-module'
export default class extends Module {
static externalTargets = ['header']
// …
}
| Kind | Name | Value |
|---|---|---|
| Singular | this.[name]ExternalEl | This first matching element in scope |
| Plural | this.[name]ExternalEls | An array of all the matching elements in scope |
| Existential | this.has[Name]ExternalEl | A boolean indicating whether there is a matching element in scope |
Naming Conventions
Always use camelCase to specify target names, since they map directly to properties on your module.