javascript-actions
Create, call and drop JavaScript actions — client-side logic called from nanoflows, not microflows. Use when behaviour must run in the browser or on the device: DOM, fetch, geolocation, or wrapping a
Files1
View on GitHubSKILL.md.claude/skills/mendix/javascript-actions/SKILL.md
GitHub<!-- skill-index: generated by scripts/skill-index.py; make check-skill-index -->
<!-- /skill-index -->
Find it fast
sed -n '<from>,<to>p' SKILL.md one section rather than reading the file;
./mxcli syntax <topic> answers how do I write this for a fraction of either.
| lines | section |
|---|---|
| 31-39 | When to Use This Skill |
| 40-51 | Overview |
| 52-94 | Syntax |
| 95-156 | Examples |
| 157-168 | Calling from a nanoflow |
| 169-193 | The generated .js file |
| 194-202 | Inspecting |
| 203-211 | Validation Checklist |
| 212-221 | Common Errors |
| 222-226 | Related Documentation |
Mendix JavaScript Actions Skill
Guidance for creating, calling, and dropping JavaScript actions in Mendix projects with MDL. JavaScript actions hold custom client-side logic and are called from nanoflows (not microflows — those use Java actions).
When to Use This Skill
- Adding client-side behaviour (browser/native APIs, DOM,
fetch, geolocation, …) - Logic that must run on the device rather than the server
- Calling an existing JavaScript action from a nanoflow
- Wrapping a marketplace/native capability exposed as a JS action
For server-side custom code, use Java actions instead (see java-actions).
Overview
A JavaScript action is two things on disk:
- The model unit (
JavaScriptActions$JavaScriptAction). - A source file
javascriptsource/<Module>/actions/<Name>.jscontaining an exportedasync function.
CREATE JAVASCRIPT ACTION writes both. The MDL body you provide becomes the
function body (between the BEGIN USER CODE / END USER CODE markers), so it
normally returns a Promise.
Syntax
CREATE [OR MODIFY] JAVASCRIPT ACTION Module.Name ( parameters )
RETURNS type
[EXPOSED AS 'caption' IN 'category']
[PLATFORM Web | Native | Hybrid | All] -- default Web
AS $$
<javascript>
$$;
DROP JAVASCRIPT ACTION Module.Name;
Clause order is fixed: returns, then exposed as, then platform, then as.
AS $$ ... $$is mandatory. Omitting the body causesno viable alternative at input '...'. Use a stub:AS $$ return Promise.resolve(false); $$.PLATFORMdefaults toWeb. UseNative,Hybrid, orAllto widen.OR MODIFYupdates an existing action in place (UUID preserved); without it, a duplicate name is an error (use create or modify to overwrite).
Parameter types
Same type system as Java actions:
- Primitives:
String,Integer,Long,Decimal,Boolean,DateTime - Entity:
Module.EntityName· List:List of Module.EntityName - Enumeration:
ENUM Module.EnumName - Type parameter (generics): declare
EntityType: ENTITY <pEntity>, then use the barepEntityfor instance parameters - Append
NOT NULLto mark a parameter required.
Parameter names in the body
The body sees each parameter with its first character lower-cased: A is
a, ReadOnly is readOnly, URL is uRL (only the first character changes),
_Lead stays _Lead. That is the signature Studio Pro and mxbuild generate, and
mxcli writes it. The model keeps the declared name and describe prints it as
declared. A body that uses the declared spelling throws ReferenceError at run
time and nothing in check or the build reports it.
Examples
Simple action (Web default):
mdl 1;
CREATE JAVASCRIPT ACTION MyFirstModule.JSA_IsOnline () RETURNS Boolean
AS $$
return Promise.resolve(navigator.onLine);
$$;
Parameters + return:
mdl 1;
CREATE JAVASCRIPT ACTION MyFirstModule.JSA_Add (
A: Integer NOT NULL,
B: Integer NOT NULL
) RETURNS Integer
AS $$
return Promise.resolve(a + b);
$$;
Exposed toolbox action, native platform:
mdl 1;
CREATE JAVASCRIPT ACTION MyFirstModule.JSA_ShowToast (
Message: String NOT NULL,
Duration: Integer
) RETURNS Boolean
EXPOSED AS 'Show Toast' IN 'UI'
PLATFORM Native
AS $$
console.log(message);
return Promise.resolve(true);
$$;
Idempotent update (UUID preserved):
mdl 1;
CREATE OR MODIFY JAVASCRIPT ACTION MyFirstModule.JSA_Add (
A: Integer NOT NULL,
B: Integer NOT NULL,
C: Integer
) RETURNS Integer
AS $$
return Promise.resolve(a + b + (c || 0));
$$;
Drop (removes the unit and the .js file):
mdl 1;
DROP JAVASCRIPT ACTION MyFirstModule.JSA_Add;
Calling from a nanoflow
JavaScript actions are invoked with CALL JAVASCRIPT ACTION inside a nanoflow
body (arguments use Name = value):
$Sum = call javascript action MyFirstModule.JSA_Add(A = 2, B = 3);
This is the nanoflow counterpart of CALL JAVA ACTION (microflows). Use it in a
CREATE NANOFLOW ... BEGIN ... END; body.
The generated .js file
CREATE writes (and OR MODIFY rewrites) javascriptsource/<Module>/actions/<Name>.js:
// This file was generated by Mendix Studio Pro.
// ...
// BEGIN EXTRA CODE
// END EXTRA CODE
/**
* @param {number} a
* @param {number} b
* @returns {Promise.<number>}
*/
export async function JSA_Add(a, b) {
// BEGIN USER CODE
return Promise.resolve(a + b);
// END USER CODE
}
Only the code between the USER CODE / EXTRA CODE markers is preserved when
Studio Pro regenerates the file. The MDL $$ body $$ lands inside USER CODE.
Inspecting
LIST JAVASCRIPT ACTIONS [IN Module];
DESCRIBE JAVASCRIPT ACTION Module.Name; -- re-executable MDL (signature + body)
DESCRIBE output round-trips: it re-parses as a CREATE JAVASCRIPT ACTION.
Validation Checklist
- Body present:
AS $$ ... $$;— never omit it - Body returns a
Promise(the function isasync) - Clause order:
returns→exposed as→platform→as - Required parameters marked
NOT NULL - Use
CALL JAVASCRIPT ACTIONfrom nanoflows,CALL JAVA ACTIONfrom microflows - Validate before applying:
mxcli check script.mdl
Common Errors
| Symptom | Cause | Fix |
|---|---|---|
no viable alternative at input '...' |
Missing AS $$ ... $$ body |
Add a body (stub return Promise.resolve(false);) |
already exists — use create or modify to overwrite |
Duplicate name without OR MODIFY |
Add OR MODIFY |
| Action runs nowhere / wrong client | PLATFORM too narrow |
Set PLATFORM All (or the right target) |
mismatched input 'platform' |
Clause out of order | Put platform after exposed as, before as |
ReferenceError: Url is not defined when the action runs |
The body uses the declared parameter name; the .js signature has the first character lower-cased |
Write url, not Url |
Related Documentation
java-actions— server-side custom code (microflows)write-nanoflows— nanoflow syntax and restrictionsmxcli syntax javascript-action— quick syntax reference