Audience: Contributor
Contract for actions and validators on persisted element nodes. Source: common/model/src/model/action.model.ts and form-validation.model.ts.
See also: Models · Values and bindings · Page structure
type EventType =
| 'click'
| 'change'
| 'mouseenter'
| 'mouseleave'
| 'visible'
| 'onLoad'
| 'submitSuccess'
| 'submitFailure';
Three host buckets (ActionOps in action.model.ts):
| Bucket | Const | Hosts |
|---|---|---|
| Interaction | INTERACTION_EVENT_TYPES |
Element action pickers (eventTypesForElement) |
| Form submit | FORM_SUBMIT_EVENT_TYPES |
Only when elementType === 'lkt-form' |
| Page lifecycle | PAGE_EVENT_TYPES (onLoad) |
Page-level actions — not on element pickers |
Do not invent event names. Put submitSuccess / submitFailure on the lkt-form host, not on the submit button. Submit controls use click + submitForm: true.
Every action has at least { event }. Behavior is selected by additional fields. Do not invent fields — copy from action.model.ts.
NavigateToPage){
"event": "click",
"pageId": 12,
"direction": "forward",
"params": {
"id": { "expr": "state.page.params.id" }
}
}
pageId: number, template key string, or { "expr": "…" } (blank/null at dispatch ⇒ navigate no-op — ActionOps.resolveNavigatePageId)direction?: 'forward' | 'back' | 'root'params?: map of IValue; authored keys that resolve blank are omitted; if every authored key is blank the navigate is a no-op (ActionOps.resolveNavigateParams)NavigateToUrl){ "event": "click", "url": "https://example.com" }
SubmitFormAction){ "event": "click", "submitForm": true, "formName": "contact" }
LogoutAction){ "event": "click", "logout": true }
ScrollToElementAction){
"event": "click",
"scrollToElementId": "ion-content_0|text_2",
"scrollBehavior": "smooth",
"scrollBlock": "start"
}
ScrollContainerEdgeAction){ "event": "click", "scrollEdge": "top", "scrollBehavior": "smooth" }
scrollEdge: 'top' | 'bottom'.
ToggleClassAction){ "event": "click", "toggleClass": "is-open", "targetElementId": "…" }
SetInteractionStateAction){ "event": "click", "interactionState": "active", "targetElementId": "…" }
Applies a named lkt-state-* class on the target.
PlayAnimationAction){
"event": "click",
"animateCss": "fadeIn",
"targetElementId": "…",
"repeat": "once",
"speed": "fast"
}
repeat / speed follow animate-css.catalog.ts.
CallAppRouteAction){
"event": "click",
"appRoute": "cart/add",
"method": "POST",
"body": { "sku": { "expr": "state.data.product.id" } },
"query": {},
"assignTo": "cart",
"onUnauthorized": { "event": "click", "pageId": 3, "direction": "forward" }
}
Hosts must enforce the installed binding clientCallableRoutes allowlist (copied from pack routes.allow at install).
AssignAppDataAction){
"event": "change",
"assignApp": "qty",
"value": { "expr": "state.event.detail.value" }
}
Writes into shared state.app at the dot path.
OpenBrowserAction){
"event": "click",
"openBrowser": true,
"url": { "raw": "https://example.com" },
"toolbarColor": "#000000",
"presentationStyle": "fullscreen"
}
Distinct from NavigateToUrl (which uses location.href).
HapticsAction){
"event": "click",
"haptics": "impact",
"impactStyle": "MEDIUM"
}
haptics: 'impact' | 'notification' | 'vibrate' (+ optional notificationType, vibrateDuration).
ShowToastAction){
"event": "click",
"showToast": true,
"text": { "raw": "Saved" },
"duration": "short",
"position": "bottom"
}
PresentActionSheetAction){
"event": "click",
"presentActionSheet": true,
"actionSheetElementId": "ion-action-sheet_0"
}
| Location | Typical events |
|---|---|
| Buttons / tappable hosts | click (+ interaction set) |
| Inputs | change |
Page (IPageDefinition.actions) |
onLoad only from PAGE_EVENT_TYPES |
lkt-form host |
interaction set plus submitSuccess / submitFailure |
| Submit control | click + submitForm: true — not form lifecycle events |
Empty actions arrays are removed by ElementReferenceOps.trim.
type FormValidatorType =
| 'required' | 'email'
| 'minLength' | 'maxLength'
| 'min' | 'max'
| 'pattern' | 'equalTo';
interface IFormValidator {
id?: number;
type: FormValidatorType;
message?: string;
field?: string; // when the rule lives on `lkt-form`
value?: string | number; // length/min/max/pattern/equalTo target
}
Hosts that may carry validators (FORM_FIELD_ELEMENT_TYPES / FormValidatorOps.supportsValidators):
lkt-form, ion-input, ion-input-otp, ion-textarea, ion-checkbox, ion-toggle, ion-select, ion-radio-group, ion-range, ion-searchbar.
{
"type": "ion-input",
"props": [
{ "name": "field", "type": "attr", "value": { "raw": "email" } },
{ "name": "label", "type": "attr", "value": { "raw": "Email" } }
],
"validators": [
{ "type": "required" },
{ "type": "email" }
]
}
Pair fields with lkt-form-error whose field prop matches the input’s field name. See lokakrt/form/children.json.
EventType and FormValidatorType values and action fields from action.model.ts.children.json.actions / validators — omit them when unused.