cattleprod v0.2.0
Cattleprod ##########
Cattleprod is a framework for declaritively adding javascript behavior to existing HTML.
A special data-controller
attribute tells controller to link an HTML element to a javascript class.
Further data-*
attributes link DOM events to methods in your class,
and make HTML elements easily accessible to be manipulated from your javascript code.
Concepts
A javascript controller class is linked to an HTML element with a
data-controller="myController"
attribute in the HTML tag.
Actions link DOM events fired from within the controlled HTML element to
named methods in the controller class.
A data-myController-actions='{"click": "handleClickEvent"}'
attribute adds an event
listener to call the handleClickEvent
method whenever a click
event is triggered.
Targets are HTML elements that are mapped to instance variables of your
controller class. A data-myController-target="myTarget"
attribute makes a DOM
element available to your class as this.myTarget
.
Values are used to pass parameters to your controller class.
A data-myController-values='{"foo": "bar"}'
attribute creates a corresponding instance
property, this.values.foo = "bar"
.
An Application object must be created to initialise your controllers and watch the DOM tree to dynamically add and remove controllers, actions, targets and values when HTML elements are created or removed.
Example
Markup your HTML to map elements to javascript controller classes::
<div data-controller="clickMe">
<div data-clickMe-actions='{"click": "doClick"}'>
Try clicking me!
<div data-clickMe-target="message"></div>
</div>
</div>
Then create a controller class and a cattleprod application::
<script type="module">
import * as cattleprod from "cattleprod.js";
class ClickMeController extends cattleprod.Controller {
// This controller has a target called ``message``,
// which corresponds to exactly 1 HTML element.
static targets = {"message": "1"}
doClick(event) {
this.message.innerHTML = "You clicked me!";
}
}
// Launch the application
new cattleprod.Application({"clickMe": ClickMeController});
</script>
How-tos
How to pass options / parameters to a controller
Add a data-<ident>-values
attribute to your controller's html tag::
<div data-controller="counter" data-messages-values='{"messageText": "Whoa nelly!"}'>...</div>
The controller must declare value names::
class ClickMeController extends cattleprod.Controller {
static values = ["messageText"]
doClick(event) {
alert(this.values.messageText);
}
}
How to look up a controller for an element
The controller for any element may be looked up from the Application instance,
using application.getController(<element>, <ident>)
. This will return the
controller attached to the given element, or the closest parent element if the
element itself is not attached to a controller.
Reference
Controllers
Controllers must extend cattleprod.Controller
. They may implement the
following methods:
`connect()`
Will be called whenever the Controller is attached to a DOM element.
`disconnect()`
Will be called whenever the Controller is detached from a DOM element.
Application
The application object sets up controllers, then monitors the DOM for changes, dynamically connecting and disconnecting controllers as required.
The Application constructor takes a single object argument, mapping string identifiers to controller classes::
new cattleprod.Application({"clickMe": ClickMeController});
In addition, application instances have a debug
attribute. If true, this
enables debug log messages in the javascript console::
cattleprod.Application.debug = true;
const app = new cattleprod.Application(...);
Events
Events are bound from the DOM to the controller by using a data attribute::
data-<ident>-actions='{"<eventName>": "<methodName>(:<eventOption>)*"}'
This maps the named event to the named controller method.
Custom events
When a controller is attached to the DOM, a cattleprod:connected
event is
dispatched to the corresponding element.
Targets
A target is a labelled HTML element or elements, that cattleprod makes accessible to the controller class as an instance property.
Target names must be registered on the controller class using the static targets property::
class SearchController extends cattleprod.Controller {
static targets = {
"results": "1"
"pagination": "+"
};
}
The values associated with each target name are:
1
The target must match exactly one HTML element. The instance property will
be a HTMLElement
object
?
The target may match zero or one HTML elements. The instance property will
either be an HTMLElement
object, or undefined.
*
The target may match any number of HTML elements. The instance property
will be an Array of HTMLElement
objects.
+
The target may match one or more HTML elements. The instance property
will be an Array of HTMLElement
objects.
The markup can then define targets as so::
<div data-search-target="pagination">...</div>
<div data-search-target="results">...</div>
<div data-search-target="pagination">...</div>
Targets are accessed from the controller instance using the defined names::
…
static targets = {
"results": "1"
"pagination": "+"
};
showResults() {
// this.esults is an HTMLElement
this.results.classList.remove("loading");
// this.pagination is an array of HTMLElement objects
this.pagination.forEach(
(n) => { ... }
}
}
Actions
Actions link DOM events to a controller. The action must be configured in the
markup using a data attribute containing a JSON mapping of <eventName>:
<handlerMethod>
::
<button data-search-actions='{"click": "refreshResults"}'>search</button>
Pass options to event listeners with::
<button data-search-actions='{"click": "refreshResults:passive:once:capture"}'>search</button>
This configuration will cause a click
event listener to be registered on
the button element, with the corresponding refreshResults
instance method
on the search controller registered as the handler. This will be called with a
single event
argument::
class SearchController {
...
refreshResults(event) {
}
}
Values
Values must be registered on the controller class using the static values property::
class SearchController extends cattleprod.Controller {
static values = ["url"];
}
Values may be declared on the same tag that contains the data-controller
attribute. Values should be declared in a data attribute named
data-<ident>-values
, containing a JSON object::
<div data-controller="search" data-search-values='{"url": "https://.../search"}'>
Data found in the JSON object will be copied into the controller instance's
values
property.