<div data-atv-controller="simple">
<button data-atv-simple-action="click">
Count 0
</button>
</div>
<script type="module">
import { activate } from '@sbrew.com/atv';
activate();
</script>
// app/javascripts/controllers/simple_atv.js
function connect() {
let counter = 0;
return {
click: function (actor) {
counter += 1;
actor.innerText = `Count ${counter}`;
}
};
}
export { connect };
div on the page.
The receiving div is the target.
<div data-atv-controller="hello">
<input data-atv-hello-target="name" type="text">
<button data-atv-hello-action="click->greet">
Greet
</button>
<span data-atv-hello-target="output">
</span>
</div>
// app/javascripts/controllers/hello_atv.js
function connect(targets) {
return {
greet: function () {
targets.output.textContent =
`Hello, ${targets.name.value}!`;
}
};
}
export { connect };
<div data-atv-controller="config"
data-atv-config-values='{"answer":"My favorite color is blue!"}'>
<button data-atv-config-action="click->reveal">
Reveal the mystery answer
</button>
<span data-atv-config-target="output">
</span>
</div>
// config_atv.js
function connect(targets, values) {
return {
reveal: function () {
targets.output.textContent = values.answer;
}
};
}
export { connect };
<div data-atv-controller="nesting">
<button data-atv-nesting-action="click">
Count 0
</button>
<div data-atv-controller="nesting">
<button data-atv-nesting-action="click">
Count 0
</button>
</div>
</div>
// app/javascripts/controllers/nesting_atv.js
function connect() {
return function () {
let counter = 0;
return {
click: function (actor) {
counter += 1;
actor.innerText = `Count ${counter}`;
}
};
};
}
export { connect };
<div data-atv-controller="multiple">
<button data-atv-multiple-actions='click click->clack' style="background-color: green;">
Count 0
</button>
</div>
// app/javascripts/controllers/multiple_atv.js
function connect() {
let counter = 0;
return {
click: function (actor) {
counter += 1;
actor.innerText = `Count ${counter}`;
return true;
},
clack: function (actor) {
actor.styles.backgroundColor = "bluegreen".replace(actor.styles.backgroundColor, "");
return true;
}
};
}
export { connect };
<div data-atv-controller="multiplier">
<input type="number" value="3" data-atv-multiplier-target="factor"></input> *
<input type="number" value="4" data-atv-multiplier-target="factor"></input> *
<input type="number" value="5" data-atv-multiplier-target="factor"></input> =
<span data-atv-multiplier-target="product"></span>
<button data-atv-multiplier-action="click->multiply">
Calculate
</button>
</div>
// app/javascripts/controllers/multiplier_atv.js
function connect(targets) {
return {
multiply: function () {
let product = 1;
targets.factors.forEach((factor) => {
if (factor.value) {
product *= factor.value;
} else {
product *= factor.innerText;
}
});
if (targets.product) {
targets.product.innerText = product;
}
return product;
}
};
}
export { connect };
<div class="product" data-atv-controller="multiplier">
<input type="number" value="1" data-atv-multiplier-target="factor"></input> *
<input type="number" value="2" data-atv-multiplier-target="factor"></input>
</div> +
<div class="product" data-atv-controller="multiplier">
<input type="number" value="3" data-atv-multiplier-target="factor"></input> *
<input type="number" value="4" data-atv-multiplier-target="factor"></input>
</div> =
<div data-atv-controller="adder">
<span data-atv-adder-target="sum"></span>
<button data-atv-adder-action="click->add">
Calculate
</button>
</div>
// app/javascripts/controllers/adder_atv.js
function connect(targets, _values, _root, controllers) {
return {
add: function () {
let sum = 0;
controllers(".product", "multiplier", (controller) => {
sum += controller.actions.multiply();
});
targets.sum.innerText = sum;
}
};
}
export { connect };
<div data-atv-controller="events">
<label for='name'>First name:<label>
<input id='name' data-atv-events-action="keydown"></input>
</div>
// app/javascript/controllers/events_atv.js
function connect() {
return {
keydown: function (_actor, event) {
const key = event.key;
if (key.length === 1 && !/[a-zA-Z]/.test(key)) {
event.preventDefault();
}
}
};
}
export { connect };
<div data-atv-controller="parameters">
<button data-atv-parameters-action="click('Count', <%= rand(2..10) %>)">
Start
</button>
</div>
// app/javascripts/controllers/parameters_atv.js
function connect() {
let counter = 0;
return {
click: function (actor, _event, params) {
const [label, increment] = params;
counter = counter + Number(increment);
actor.innerText = `${label} ${counter}`;
}
};
}
export { connect };
<div data-atv-controller="divider, multiplier">
(<input type="number" value="12" data-atv-divider-target="dividend"></input> /
<input type="number" value="3" data-atv-divider-target="divisor"></input>) =
<span data-atv-divider-target="quotient" data-atv-multiplier-target="factor"></span> *
<input type="number" value="6" data-atv-multiplier-target="factor"></input>) =
<span data-atv-multiplier-target="product"></span>
<button id="button" data-atv-actions="click->divider#divide, click->multiplier#multiply">
Calculate
</button>
</div>
// app/javascripts/controllers/divider_atv.js
function connect(targets) {
return {
divide: function () {
if (Number(targets.divisor.value) === 0) {
targets.quotient.innerText = "You can't divide by zero!";
return false;
}
return targets.quotient.innerText =
Number(targets.dividend.value) / Number(targets.divisor.value);
}
};
}
export { connect };
If a new controller appears in the DOM it will receive the connect method at that time.
Also note that connections receive a third parameter of the hosting element, as seen in the connecting_atv.js below.
When targets are added to the DOM, if the controller has a targetTargetConnected
method, that method is called with the DOM element as its parameter.
targetTargetDisconnected is also available for when a target is removed from the DOM.
<div data-atv-controller="connecting">
<button data-atv-connecting-action="click">
Create
</button>
<span data-atv-connecting-target="state">
Not yet connected.
<span>
</div>
// app/javascript/controllers/connecting_atv.js
function connect(targets, _values, root) {
return {
click: function () {
root.insertAdjacentHTML("afterend", `
<div data-atv-controller="connecting">
<button data-atv-connecting-action="click">
Create
</button>
<span data-atv-connecting-target="state">
Not yet connected.
</span>
</div>
`);
},
stateTargetConnected: function (element) {
targets.state.innerText = "Connected";
}
};
}
export { connect };
<div data-atv-controller="disconnecting">
<button data-atv-disconnecting-action="click">
Disconnect
</button>
</div>
<span id="disconnected-state">
Not yet connected.
<span>
// app/javascript/controllers/disconnecting_atv.js
function connect(_targets, _values, root) {
const connectedStateDiv = document.getElementById('disconnected-state');
connectedStateDiv.innerText = "Connected";
return {
click: function () {
root.parentNode.removeChild(root);
},
disconnect: function () {
connectedStateDiv.innerText = "Disconnected";
}
};
}
export { connect };
<div data-my-atv-controller="simple">
<button data-my-atv-simple-action="click">
Count 0
</button>
</div>
<script type="module">
import { activate } from '@sbrew.com/atv';
activate("my-atv");
</script>
// app/javascripts/controllers/simple_atv.js
function connect() {
let counter = 0;
return {
click: function (actor) {
counter += 1;
actor.innerText = `Count ${counter}`;
}
};
}
export { connect };
Brought to you by sbrew.com.