> For the complete documentation index, see [llms.txt](https://docs.wem.io/platform/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wem.io/platform/wemreference/wem-widgets/wemscript-for-widgets.md).

# WEMScript for Widgets

{% hint style="warning" %}
Please read [our info on Content Security Policy](/platform/wemreference/content-security-policy.md) introduced in 4.2.
{% endhint %}

Besides the [WEMScript for Custom HTML](/platform/wemreference/wemscript-for-custom-html.md), WEM also has WEMScript with specific features to use when creating Custom WEM Widgets.

WEMScript is a specific script created by WEM to make it possible to use specific WEM Elements (properties, fields, events, functions) available to the Script Editor in the Widgets. This is typically the low-code part of WEM.&#x20;

## Statements

### if

General usage:

```
if <expression>
    statements...
elseif <expression>
    statements...
else
    statements....
end
```

The `elseif` and `else` parts are optional. The expressions of the `if` and `elseif` statements should return a boolean (true/false).

### while

General usage:

```
while <expression>
    statements...
end
```

The expression after `while` should return a boolean (true/false) - all statements between `while` and `end` will be executed as long as the while-expression is true.

### var

There are two ways to declare a variable:

```
/* declare a variable, the initial value is "unknown" */    
var @a : type

/* declare a variable and assign an initial value */
var @b := expression
```

The type of variable `@b` is derived from the expression. The following types are supported by wem:

`actionflowchart`, `boolean` , `buttonexit`, `concept`, `conceptset`, `datetime`, `duration`, `file`, `hyperlink`, `list`, `multiselect`, `navigationitem`, `number`, `richtext` and `text`.

### arrays

Array variables are available in WEMScript. Array variables are declared as follows:

```
var @numbers : array<number>;
var @dates : array<date>;
var @concepts : array<concept>;
...
```

The type `array<T>` is generic, but `T` can itself not be an array type. The following declaration is **not** supported:

```
var @arr : array<array<number>>;
```

An array variable is never `null` (or `unknown`). As soon as the variable is declared, an empty array is instantiated. The following methods can be used to add or remove values from an array:

```
var @primes : array<number>;

/* Add the numbers 2 and 3 to @primes */
add 2 to @primes;
add 3 to @primes;
```

The new values will be appended to the end of the array. If you only want to add a value if it is not already in the array, then you can use the `unique` keyword:

```
/* Unique keyword ensures that the number 5 will only be added once. */
add unique 5 to @primes;
add unique 5 to @primes;
```

You can use the `remove` statement to remove values from an array:

```
remove 5 from @primes;
```

Use the `count()` function to get the length of an array. Other aggregation functions are also available, such as `concat()`, `max()`, `min()`, `sum()` and `average()`.

```
var @cities : array<text>;

add "Amsterdam" to @cities;
add "London" to @cities;
add "Paris" to @cities;

/* Prints "3" */
print count(@cities);

/* Prints "Amsterdam, London, Paris" */
print concat(@cities);
```

You can initialize an array by using the `list()` function.

```
/* A list of the first 10 primes. */
var @primes := list(2,3,5,7,11,13,17,19,23,29);
```

Use parentheses to get the value at a specific index. The index is **one-based** (meaning the first element has index value of 1):

```
print @primes(1); /* prints "2" */
print @primes(3); /* prints "5" */
```

If the index is out of bounds, then the result will be `unknown`. You should not get an error in the script when this should happen.

You can use the `in` operator to check if the array contains a certain value:

```
var @list := list(2,3,5,8,13)

if (3 in @list)
    print "3 is in the list"
end
```

### register

The `register` statement can only be used in render scripts and is used to indicate to the runtime that a form `<input>` field will be rendered that is bound to a Data Field item from the project Data Model. This enables two-way binding. General usage:

```
register input <data-field> [required = <expression>], 
    [notrim = <expression>],
    [precision = <expression>], 
    [include time = <expression>], 
    [unit = day|hour|minute|second],
    [invariant culture],
    [base64 = <expression>]
```

The most basic use is `register input <data-field>`. This can followed by some (optional) annotations:

* `required` – annotates that the user is required to provide a value.
* `notrim` – by default all the user input is trimmed. Use this annotation to disable trimming. The `= <expression>` part is optional.
* `precision` – this annotation is only valid for `number` and `duration` data-fields. The precision should be a numeric value between `-1` and `12` (including). If the precision is `-1`, or if the precision is omitted, then precision is limited by the 64bit float (double) that stores the value.
* `include time` – this annotation is only valid for `datetime` data-fields. It states that it expects that the user specifies both the date and the time.
* `unit` – this annotation is only valid for `duration` data-fields. Possible values are `day`, `hour`, `minute`, and `second`.
* `invariant culture` – this annotation is only valid for `number`, `duration` and `datetime` data-fields. It states that it always expects the user input to be in an international (US English) format. For dates, it means that the input should be a valid ISO8601 format. For numeric values, it means that the `.` should be used as the decimal point (and comma as thousand-separator).
* `base64` - this annotation is used for File Input Properties.

The annotations `required`, `notrim`, `include time` and `invariant culture` can be used with or without an expression. If it is used without an expression, then `<annotation> = true`. is implied.

Examples:

```
register input [StartDate] required, invariant culture
register input [Length] precision = @precision, invariant culture
register input [Appointment.Duration] precision = 0, duration = minute
register input [Password] required, notrim
register input @ImageFileProperty base64 = true
```

The order in which the annotations are stated is not relevant.

{% hint style="info" %}
Files that are part of the datamodel are stored in Base64 and may be prefixed with a filename and semicolon. For example if your Widget uses a canvas element you can create and store an image based on that canvas by using the Javascript toDataUrl function. That function returns a data URL containing Base64 data, the data you can use to store images. Note that WEM is only interested in the data, with an optional filename prefix.&#x20;

If your data URL is: \
"`data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ…ADAMBAAIRAxEAPwD/AD/6AP/Z`"&#x20;

you need to remove "data:image/jpeg;base64,".&#x20;

A valid value with a filename prefix would be: \
"`image.jpg;/9j/4AAQSkZJRgABAQ…ADAMBAAIRAxEAPwD/AD/6AP/Z`".
{% endhint %}

### print

Print statements can only be used in render scripts.\
The general usage is:

```
print [html|attr|js] <expression>
```

Renders the result of the given expression. If `html` is provided, then the result will be html encoded; if `attr` is provided, then the result will be html attribute encoded.

### loop

General usage:

```
loop <expression>
    statements...
end
```

The result of the expression should be "iterable". That is, it should either be a (filtered) list or a concept set. This means the following examples are valid:

```
/* list */    
loop [Products]
    statements...
end

/* filtered list */
loop [Products] where [Price] > @MinPrice
    statements...
end

/* concept set */
loop [SelectedLocations]
    statements...
end

/* GetChildren() returns a concept set */
loop GetChildren([SelectedLocation]) 
    statements...
end
```

When looping through a concept set, you can use the keyword `concept` to reference the current concept within the loop.

### follow

The `follow` statement can only be used in the event-handler script of a Widget.\
The general usage is:

```
follow @buttonExit
```

This statement will terminate the script and follow the given (button) exit.

### execute

The `execute` statement can only be used in the event-handler script of a Widget.\
The general usage is:

```
execute @actionFlowchart
```

This statement will execute the given (action) flowchart. After the flowchart is executed, it will continue the execution of the event-handler script.

### navigate to

The `navigate to` statement can only be used in the event-handler script of a Widget.\
The general usage is:

```
navigate to <expression>
```

This statement will terminate the script and redirect the user to the given location. The given expression should return a `navigationitem`, `hyperlink` or `string`. If the return type is a `string`, it will be interpreted as a URL (hyperlink).

### scriptmodule

The `scriptmodule` statement can only be used in the render-script of a Widget.\
The general usage is:

```
scriptmodule <expression>
    statements...
end
```

Use the `scriptmodule` statement to add JavaScript code that your widget needs. This JavaScript code will be **added to the page only once**: the first time that the widget is used on the page. This makes it possible to add a Widget more than once on a Template while the code being used is only added once to the output (optimizing the HTML response).

### scriptreference

The `scriptreference` statement can only be used in the render-script of a Widget. \
The general usage is:

```
scriptreference <key-expression> <src-expression>
```

Use the `scriptreference` statement to add a JavaScript reference that your widget needs. This JavaScript reference will be added to the page only once: the first time that the widget is used on the page.

### startupscript

The `startupscript` can only be used in the render-script of a Widget. The `startupscript` block will be invoked after the whole HTML result has been rendered. You can use this code block to initialize instances in JavaScript.

The general usage is:

```
<? startupscript ?>
    /* JavaScript code */
    MyJsLibrary().init();
<? end ?>
```

### submitscript

The `submitscript` can only be used in the render script of a Widget. The `submitscript` block will be invoked before the new request is sent, for example immediately after a button click. You can use this code block to alter the input data before it will be send with the request.

The general usage is:

```
<? submitscript ?>
    /* JavaScript code */
    var myField = document.getElementById("my-field-" + <?js OutputId()?>);
    myField.value = myField.value.trim().toLowerCase();
<? end ?>
```

### unloadscript

The `submitscript` can only be used in the render-script of a Widget. The `unloadscript` block will be invoked after the request has responded but before the new HTML has been drawn. You can use this code block to cleanup JavaScript instances before drawing the new HTML.

The general usage is:

```
<? unloadscript ?>
    /* JavaScript code */
    MyJsLibrary().dispose();
<? end ?>
```

### once

The `once` statement can only be used in the render script of a Widget.\
The general usage is:

```
once
    statements...
end

once <expression>
    statements...
end
```

The `once` statement can be used to make sure that an html fragment is only added to the page (html-output) once. You should **not** use this keyword to add scripts. Use the `scriptmodule`, `scriptreference` or `startupscript` statements to add scripts in the correct way.

## Keywords

### OutputId

This keyword is only available in render scripts and will return the WEM output Id for the current custom control or for the given data-field. Usage:

```
/* Returns the output Id for the custom control */     
OutputId()

/* Returns the output Id for a data-field within the current context */
OutputId([MyDataFieldItem])
```

An example that uses the `id` keyword in combination with the register input field to create a custom control for text input. It assumes that the property `@DataField` exists and is bound to a text datafield.

```
<? register input @DataField required = true ?>
<input type="text" name="<?attr OutputId(@DataField) ?>" value="<?attr @DataField ?>" />
```

When the custom control properties are resolved, it will become something like this:

```
<? register input [MyDataFieldItem] required = true ?>
<input type="text" name="<?attr OutputId([MyDataFieldItem]) ?>" value="<?attr [MyDataFieldItem] ?>" />
```

### range of

The `range of` keyword returns the range of a concept (or concept set) data-field (single-select or multi-select). Usage:

```
range of [MyConceptSet]
```

This is an expression that returns a concept set. You can use this construct as part in a bigger expression:

```
if (@MyConcept in range of [MyConceptSet]) then "Yes" else "No"
```

The `range of` keyword is very useful when making a custom control bound to a concept (set) data-field. For the following example, assume that `@ConceptSet` is a property that is bound to a concept set data-field:

```
<? loop range of @ConceptSet ?>
    var @className := concept in @ConceptSet ? "highlighted" : "dimmed";
    <div class="<?attr @className ?>"><?= concept ?></div>
<? end ?>
```

### Order By

The `order by` keyword is used to sort the result of an iterable expression, such as a list or concept set. It is typically used in combination with the `loop` statement or other expressions that return collections.

```
loop <expression> order by <field/expression> [asc|desc]
    statements...
end
```

* `<expression>` must return an iterable (e.g. list or concept set).
* `<field/expression>` determines the value used for sorting.
* `asc` (ascending) is the default if not specified.
* `desc` (descending) can be used to reverse the order.

### invalidvalue

This keyword is only available in render-scripts. The `invalidvalue` keyword returns the invalid value that is stored in the given data-field. It returns null if the value of the given data-field is valid. Usage:

```
invalidvalue [MyDossierItem]
```

The use case for this keyword is to get the invalid value that the user provided. For the following example, assume that `@number` is a property that is bound to a numeric data-field:

```
<? register input @number precision = 2 ?>
<? var @value := invalidvalue @number ? Format(@number, 2) ?>
<label>Enter a value:</label>
<input type="text" name="<?attr id(@number) ?>" value="<?attr @value ?>" />
```

## Viewstate

The **`viewstate`** is accessible and modifiable in the Runtime. The WEM `Runtime.js` has an API that widgets can use to read and modify the **`viewstate`**. This greatly improves the possibilities of a widget.

```
/* Read some value from the viewstate. */
var value = Runtime.viewState(outputId).get("key");

/* Write a value to the viewstate. */
Runtime.viewState(outputId).set("key", value);

/* Remove a value from the viewstate. */
Runtime.viewState(outputId).clear("key");

/* Clear the entire viewstate for a given control. */
Runtime.viewState(outputId).clear();
```

You can define Viewstate fields in the Viewstate tab.\
The type of a field is restricted to one of the following:

```
Text, RichText, Number, Boolean, Date and Duration
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.wem.io/platform/wemreference/wem-widgets/wemscript-for-widgets.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
