Skip to main content

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:

KindNameValue
Singularthis.[name]ElThis first matching element in scope
Pluralthis.[name]ElsAn array of all the matching elements in scope
Existentialthis.has[Name]ElA 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']

// …
}
KindNameValue
Singularthis.[name]ExternalElThis first matching element in scope
Pluralthis.[name]ExternalElsAn array of all the matching elements in scope
Existentialthis.has[Name]ExternalElA 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.