β‘ ActionsΒΆ
Actions are the bridge between HTML and JavaScript in Clera. An action is a JavaScript function that runs when an element is clicked or a form is submitted.
π Declaring an actionΒΆ
Add the action attribute to any element:
<button action="openMenu">Menu</button>
<div action="dismissAlert">β</div>
For forms, use action on the <form> element:
<form action="addTask">
<input name="title" placeholder="Task title">
<button type="submit">Add</button>
</form>
βοΈ Writing the functionΒΆ
Write a plain JavaScript function with the same name:
function openMenu() {
// runs when the button is clicked
}
function addTask(context) {
const title = context.values.title;
// runs when the form is submitted
}
That is all. No registration. No imports. Clera finds the function by name.
β‘ Action resolution orderΒΆ
When an action is triggered, Clera looks for the handler in this order:
Page-local actions: registered via
app.page("pageName", { actions: { ... } })Global registered actions: set via
app.actions = { ... }Global functions: plain
function myAction() {}found viawindow["myAction"]
The first match wins. If nothing is found:
[CLERA:ACTION_NOT_FOUND] Action "addTask" not found on page "home".
β οΈ Exact name matchΒΆ
The HTML action attribute value must match the JavaScript function name exactly:
<button action="addTask">Add</button> <!-- looks for: function addTask() -->
<button action="AddTask">Add</button> <!-- looks for: function AddTask(): different! -->
π― context is optionalΒΆ
Clera always passes context as the first argument. Declaring it in the function signature is optional:
// Both are valid:
function openMenu() {
console.log("Menu opened");
}
function openMenu(context) {
console.log("On page:", context.pageName);
}
JavaScript ignores extra arguments automatically.
β‘ Async actionsΒΆ
Actions can be async. Clera handles the returned Promise and logs any unhandled rejections to the diagnostics console:
async function loadData(context) {
const response = await fetch("/api/data");
const data = await response.json();
context.render("#content", data.html);
}
π― Inline argumentsΒΆ
Arguments can be passed directly in the action attribute. Two syntaxes are supported and are fully equivalent:
Colon syntax: action="fnName: arg1, arg2"
<button action="deleteTask: 42">Delete</button>
<button action="setMode: 'dark'">Dark</button>
<button action="toggle: true">On</button>
<button action="move: {task.id}, 'done'">Move</button>
Function-call syntax: action="fnName(arg1, arg2)"
<button action="deleteTask(42)">Delete</button>
<button action="setMode('dark')">Dark</button>
<button action="toggle(true)">On</button>
<button action="move({task.id}, 'done')">Move</button>
The runtime converts function-call syntax into colon syntax before parsing. Both produce identical results. Use whichever reads more naturally in context.
Reading args in the handlerΒΆ
Args land on context.args (frozen array) and context.arg (first item shorthand, null when no args):
function deleteTask(context) {
const id = context.arg; // 42, first arg shorthand
}
function move(context) {
const id = context.args[0]; // resolved value of {task.id}
const status = context.args[1]; // "done"
}
function noArgs(context) {
context.arg; // null
context.args; // []
}
Supported arg typesΒΆ
Written in HTML |
JS type |
Value in handler |
|---|---|---|
|
number |
|
|
string |
|
|
boolean |
|
|
null |
|
|
state binding |
value at |
String args must be wrapped in single or double quotes. An unquoted word that is not a known literal (true, false, null) or a number is passed through as a plain string:
<button action="setTab: overview">Overview</button>
<!-- context.arg === "overview" -->
State bindings ({path}) resolve from page-local data first, then global data, at the moment the element is clicked. They are not re-evaluated on render cycles.