Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The following pages provide an introduction to writing scripts with Ninox
The Ninox script language (also "NX script language" or "NX script") is designed to automate simple, repetitive operations, as well as complex work sequences, to provide optimal support for your workflows.
We don't distinguish between functions and procedures in the following.
A function returns a specific result based on values of parameters.
A procedure executes a series of successive individual actions.
Ready? Let's go...
This is where you do magic... uh... script
The input of functions or procedures is done via the formula editor in a formula field (always indicated by fx).
These fields are the "entrance" to the formula editor. We collected a few examples for you below.
The most important operators for writing scripts
Operator | Description | Examples |
---|---|---|
Create simple arithmetic operations
These operators let you take 2 numeric values, perform a calculation, and return a numeric value. This is mainly about basic arithmetic operations.
Operator | Description | Example |
---|---|---|
Ninox removes
superfluous parentheses—following the precedence rule "first the division, then the addition")—and
superfluous white spaces.
However, Ninox also adds white spaces where they are deemed useful, e.g., for better readability).
let
Create a new variable with let
and assign a value to the variable using :=
.
The name of the variable must not be a keyword. For example, let let
is not allowed.
Result: Hello Sam! (if the name Sam is pulled from the First Name field)
You can use var
instead of let
to declare a variable. We recommend using let
as var
is a bit outdated.
An overview of all basic features the formula editor offers as of version 3.6.0
At the moment, the new formula editor features are available for the web app () as well as the Mac app.
Line numbers are displayed in the left margin of the formula editor window.
Line numbers are always visible by default.
Indents a code block automatically.
Takes your code and prettifies it to conform to a consistent style. Wraps code and adds or removes white space when necessary.
Access the formula editor to format existing code, click OK to leave the editor. The next time you open the formula editor again, this code appears newly formatted.
While you type, a pop-up appears next to the cursor displaying suggestions to complete your script.
To select the first option from the list, press the ENTER
key.
To select another option, use the arrow keys, then confirm your selection with the ENTER
key.
While you type, text is highlighted in different colors.
To trigger syntax highlighting, type an expression.
The current location of the written code is displayed above the formula editor's contents.
The location is displayed automatically.
Displays errors and warnings while you script and suggest corrections.
While you type, gutter line numbers with erroneous code are highlighted and the code itself is underlined in red. To reveal the error message, hover above the line number.
When you make a syntax error, the formula editor only highlights the first error, even when more syntax error follow that first one. This happens because the following script cannot be parsed due to the preceding syntax error. When you make a reference error, the formula editor highlights each error independently of its position in the script. So, when a syntax error precedes a reference error, only the foregoing syntax error is highlighted.
Search and replace text, variables, and expressions within a code block. Works for
Match Whole Word
,
Match Case
, and
Use Regular Expression
.
To search, enter text in the search bar or press CMD+F
(macOS) or Ctrl+F
(Windows).
Highlights corresponding parentheses and automatically completes open parentheses.
To visually locate a parenthesis' match, use the arrow keys to select a parenthesis and highlight its counterpart.
To auto-complete parentheses, type an opening parenthesis.
if ... then ... else ... end
Use if ... then ... else ... end
to specify an if-then-else conditional statement that has Ninox check whether a sequence of statements should be executed (if... then...) or what should happen when the input condition is not met (... else...).
The if statement must be an expression that is either true
/yes or false
/no.
The use of comparison operators, such as greater than (>=
), less than (<=
) or equal to (=
) is also suitable for this purpose.
Depending on the result of the comparison, the further procedure is determined.
Create a Total field (number field type), type the following script in a formula field, and vary the value to Total:
Result: If the entered value in the Total field is greater than or equal to €30, payment is made by Card, otherwise payment is made in Cash.
You don't need to specify an alternative sequence, e.g., an else
. This means that a statement is either executed or not.
Result: paymentMethod
is set to Cash by default. However, if the value in the Total number field is greater than €30, the value for paymentMethod
is updated to Card.
Use null
to check whether a data field is empty. So null
does not stand for 0, but for empty. Combined with a branch, it allows you to execute a script even when a field is empty.
Result: If the Total field is empty, a prompt ("Please enter an amount!"
) is displayed.
Syntax | Color |
---|
:=
A "defined as equal to" operator assigns a value to a field or variable.
Text := "Hello world!"
let x := 1000;
x := 2
;
A semicolon ends a line. If you define variables (with let
), the semicolon is also inserted automatically and subsequently by Ninox.
let x := 1000;
""
Double quotes highlight text, i.e., everything inside should be used as normal text.
"Hello" + " " + "world!"
=> Hello world!
Text := "Hello world!"
=> Hello world!
''
Single quotes enclose table or field names that contain spaces or special characters so that Ninox detects they belong together.
'Total net' + " " + "(VAT not included)"
=> 425,00 € (VAT not included)
Note: 'Total net'
is a field name in your database.
"(VAT not included)"
is text appended to the amount.
.
A dot lets you access fields of records or values of JSON objects.
For example, access all customer IDs in the Customers table with (select Customers).CustomerIDs
.
--- ---
An alternative to double quotes (see above) is a 3 minus sign to help make dynamic text more clear.
---Hello world!---
=> Hello world!
+
Addition (also for joining text)
1 + 2 = 3
-
Subtraction
3 - 2 = 1
*
Multiplication
2 * 3 = 6
/
Division
6 / 3 = 2
%
Modulo
13 % 5 = 3
(13 / 5 = 2 Reminder 3)
()
Parentheses (to change the order in which expressions are processed)
1 + 2 * 3 = 1 + (2 * 3) = 7
(1 + 2) * 3 = 9
create | delete
To create a record in a specific table by script, specify the corresponding table name in a button after create
.
Result: A new, but empty record in the Customers table.
To fill this new record with data, first store the expression in a variable and then use the variable to access the desired fields.
Initialize the variable newCustomer
with the expression create Customer
to store the record in the variable.
Access the fields of the new record using the dot operator .
and give the new record a unique Customer number consisting of the letter C
and a UNIX timestamp.
Result: A new record in the Customers table with a unique customer number.
Delete records automatically by specifying which records to delete after delete
.
Insert the following script in a button to delete the current record.
This is useful for linking the deletion process to another action, such as triggering an email before the record is removed.
Result: The current record is deleted.
To delete several records, combine delete
with select
.
Result: All records in the Customers table with the status 4
are deleted.
Make texts dynamic via a script
To personalize texts, for example, send a letter that looks basically the same as an invoice to many recipients with the respective other data, this is easier to do with dynamic texts (see birthday greetings).
To make texts dynamic using a script, you have 2 options:
Connect simple strings and fields with the plus operator +
.
Template strings with values inside braces {...}
.
Concatenate simple strings with the +
operator. Use +
to include any data type, e.g., numbers.
At least one of the data types must be a string, so that the output is also a string.
In a table, create a First Name field and paste the following content into a formula field.
Result: Hello Sam! (if the First name field contains the value Sam)
Template strings are indicated by a 3 minus signs ---
at the beginning and end. Everything in between turns into text.
Put braces {...}
around scripts, e.g., to write a serial letter that fetches the relevant data, such as first and last name, address, etc., from a table.
Same as above, but with a template string.
Result: Hello Sam! (if the First name field contains the value Sam)
String (text) |
Keyword |
Function |
Built-in value |
Variable/Table/Field |
Operator |
Number |
Data type |
for ... in ... do ... end | for ... from ... to ... do ... end | while ... do ... end
Loops allow you to automatically execute a code block multiple numbers of times in succession. For example, apply the statements of a code block to each element of an array.
One of the most important loops you need to know about—it'll be very helpful when writing your scripts.
After for
, select the corresponding variable name for the item in the list that you want to change.
for
loop is structured as follows:Line 1: Not yet part of the loop but useful because it's easier to read: the records are stored in a variable.
Line 2: The loop starts with for
[it follows a label for a single element from the list to be traversed] in
[it follows the list] do
.
Line 3: statement of what should be done.
Line 4: end
terminates the loop (termination).
You'd like to assign all customers who have status 2
a new one, status 1
. First, select the customers with status 2
in the Customers (new) table. Then assign status 1
to each of these customers (customer
).
Result: All customers who have status 2
are assigned status 1
.
This loop is especially suitable when working with numeric values since instead of an array, a sequence of numbers will be iterated.
On each pass, 1
is added to the loop variable (increment = 1
). It starts with the value after from
(inclusive) and ends before the value after to
(exclusive).
Result: 60
The values of the array with the indices 0
, 1
and 2
are added. 10
+ 20
+ 30
= 60
.
Change the height of the increment with step
.
Result: 50
The values of the array with the indices 0
, 2
and 4
are added. 10
+ 30
+ 10
= 50
.
for i in range(0, 10)
is the equivalent of for i from 0 to 10
.
This loop is executed until the condition after while
is no longer true.
Declare a counter variable, for example, which is incremented on each loop pass until the condition is no longer true. The condition is correct (true
) as long as the variable is less than a specified value.
Result: 0 1 2 3 4 5 6 7 8 9
In most cases, for ... in ... do ... end
is the preferred choice.
order by
Use order by
to sort an array of records by a specific field. This is useful when sorting an array first before processing it further.
When you use order by
in a View layout item, it is first sorted by a (selected) column header and second by the value specified after order by
.
order by
works best when you sort records by a number.
Result: The entries of the Invoices table are sorted by the Total field (from small to large).
Restrict the selection of records with where
or brackets [...]
.
The value after order by
does not necessarily have to be a field name, it can also be manipulated by functions, for example.
Result: The entries with today's date of the Invoices table are sorted by the number in the Invoice no. text field.
3
refers to the position of the number within the invoice no., which in our case, for example, starts with the 4th position: NO-12574
(0
=N
, 1
= O
, 2
=-
, 3
= 1
(the first number)).
Order by
works best when you sort records by a number.
Be careful when sorting strings. Strings are not sorted alphabetically, but according to the index of the characters. So first all upper case letters are sorted alphabetically, then the lower case letters.
ABcD is thus sorted to ABDc. To get the desired result, simply unify the values by upper()
or lower()
. Then all initial letters are first set to upper case or lower case respectively.
Result: ABcD
Alternative: Use the Ninox function sort()
instead of order by
.
You have a table Example for order by with a First name field. It contains the following records: Aaron, Eddi, conrad, beate, Dahlia, and Fatima. Insert the following script into a formula field.
Result: Aaron, Dahlia, Eddi, Fatima, beate, conrad
This is not the desired alphabetical sorting...
We add upper()
, which sets all entries to upper case for sorting.
If you only need the list of names and not the records themselves, we recommend using sort()
:
Result: Aaron, beate, conrad, Dahlia, Eddi, Fatima
select ... where
select
lets you access any record of any table within a database using a script. Enter the name of the table from which you want to pull records after the select
command.
Insert the following script in the options of an embedded table view under Formula to display all the records of the Customers (New) table.
Result: All records of the Customers (new) table are displayed in an embedded table.
To avoid displaying all records of a table, limit the selection with select ... where
. Then only the records are displayed which fulfill the condition after where
.
In the Customers table, a choice field Headquarter is available, in which the IDs of the choice values are assigned as
1
= Germany
2
= Austria
3
= Switzerland
4
= France
5
= Spain
6
= Italy
and you'd like to display only the DACH region, i.e., Germany, Austria, and Switzerland.
Result: In an embedded table the records of the table Customers (new) are displayed, which have their company headquarters in 1
(Germany), 2
(Austria), or 3
(Switzerland).
In case you use special characters in a field or table name, e.g., white space, hyphen, underscore etc., put the name between 2 single quotes ('...')
.
... where
You may further filter already selected records, i.e., an array of type [nid
], by specifying the condition to filter by in brackets [...]
after the array.
In contrast to select ... where
, all records are selected first and then filtered. With select ... where
only the records that meet the conditions are selected.
Do you want to dive deeper into the topic? Take a look at the corresponding part of our video tutorial.
The Ninox 3.11 release introduces "Creatable if" and "Deletable if"—set conditions for record creation and deletion with the formula editor
Creatable if and Deletable if are available for all apps (web app, iPhone/iPad, Mac, Android).
In Ninox 3.11, the functions isAdminMode()
, clientLang()
, and userLang()
are mainly for client-side use. When used with Creatable if and Deletable if features, they give false results because they rely on client-side data, which is not available for server-side processes.
Conditional data management
Creatable if allows for record creation only under specific conditions, for more control over when data is generated.
Deletable if blocks records from being deleted by mistake or without authorization, which safeguards data integrity.
Enhanced compliance
Admins can apply rules that restrict certain actions, such as deleting sent invoices, to ensure adherence to policies.
Increased data efficiency
Admins can manage the life cycle of records, which avoids creating unnecessary or duplicate entries. This makes data handling more efficient.
Greater control in user workflows
Users can only create or delete records under specific conditions or through designated actions, which provides tighter oversight of user activities.
Easier workflow automation
Parts of the workflow, like creating or removing records automatically when certain criteria are met, are streamlined for efficiency.
The features Creatable if and Deletable if offer a nuanced approach to managing data within the formula editor. This is in contrast with the pre-existing methods of create records and delete records, where you only select a user role from a dropdown menu.
While the latter work as a shortcut to manage creation and deletion based on user roles, Creatable if and Deletable if let you specify more precise conditions in the formula editor.
Start by creating a new database:
Go to your workspace and click the New database tile.
Select a database template:
Choose the Offers and invoices template from the list.
Access your database:
Once the database is created, open the Offers and invoices database.
Navigate to the Invoices table:
Within your database, find and click the Invoices table.
Edit fields:
Set permissions:
In the settings pop-up, click Creatable if or Deletable if (3) to define conditions.
Configure conditions:
Use the formula editor that opens to set up your conditions as per the examples provided.
In the formula editor, type userHasRole("Supervisor")
. This means only users with the Supervisor role can create records.
Click Save to close the formula editor.
Click Save in the table settings to apply changes.
To test, attempt to create a record by clicking the plus icon. If unauthorized, a message saying You are not authorized for this action will appear.
In the formula editor, type Status = 1
. This means records with the status Open can be deleted.
Click Save to close the formula editor.
Click Save in the table settings to apply changes.
To test, attempt to delete a record not marked as Open by clicking the trash icon. Upon confirmation, if unauthorized, a message saying You are not authorized for this action will appear.
do as transaction ... end | do as server ... end | do as deferred ... end
Ninox executes scripts in a perpetual exchange between the browser or app and the server. Usually, this works fine because the exchange is fast enough to process a script quickly.
However, in some cases you may further optimize the performance of your scripts by placing instructions in special code blocks.
More about Tips and tricks for fast databases.
To ensure scripts are executed within the same transaction, it's best to use do as transaction
.
do as transaction
was developed specifically for mobile apps (iPhone, iPad, Android) and desktop app (Mac) to process scripts locally. For example, when the internet connection is interrupted.
When use do as transaction
in the web app, the script is always executed on the server.
The nesting of loop and select
commands is usually very performance-heavy, so we recommend wrapping such scripts in a do as transaction
block to speed up the process.
If there are any issues executing the script for whatever reason, the transaction is discarded, i.e., a transaction is either executed completely or not at all.
More about Transactions.
Let's assign a Contact from the Contacts table a matching ID to the Contact field in each record of the Companies table. The entire process is executed within do as transaction
.
Result: All records in the Companies table are linked to an entry from the Contacts table within one transaction.
Occasionally, it may be beneficial to fully execute a portion of your script on the server first, before sending it back to your computer or app.
We don't recommend using do as server
in triggers because triggers in a browser are always executed on the server as well as locally in the app. Rather use do as server
in buttons.
do as server
is most often used in conjunction with the http()
function to execute API calls server-side first. This bypasses the browser's CORS (cross-origin resource sharing) policy, which would otherwise block the http
call. Then you receive the requested data from the server.
More about API calls.
Some functions cannot be executed on the server because they are related to your browser or app, e.g., alert()
.
Let's get some data from a table in a database. First, you send a GET
request to the respective database. Using the dot operator .
, access the values of the response
.
Result: The result
value of the response
is returned, which in this case consists of only one record and the information contained in the individual fields.
Normally Ninox executes write transactions in sequence.
Tip: Get familiar with the difference between Read transactions and Write transactions.
Some of these write transactions may take more time, causing subsequent transactions to wait a bit. This may cause Ninox to slow down unintentionally.
Use the do as deferred
statement to ensure read transactions within a write transaction are split off into a separate (read) transaction—all of which can be executed in the background.
When you modify data in a large table, this may take several seconds instead of a few milliseconds. Downstream statements then have to wait until all data is completely modified.
do as deferred
speeds up the processing of statements because statements that occur between do as deferred
and end
are processed separately and thus do not interfere with other processes.
Optimize a status change with a resulting triggered email as follows.
Set a field Status = 3
. This causes the trigger stored in the Status field to trigger after change the following instructions (see code block):
The field sent on is set to today's date.
An email with a payment request is sent. This is executed separately.
Result: All records whose status is set to 3
have today's date stored in the Sent On field. In a detached transaction, an email requesting payment is also sent to all records with the status 3
.
Two values are compared with each other
This allows you to compare 2 numeric values. The operators return a result that is either true or false. The output in the Ninox field is Yes (true
) or No (false
).
Operator | Description | Examples |
---|---|---|
function
Create your own functions with Ninox to automate workflows according to your needs.
write a script once and use it throughout the database
concise scripts because you only need your own function and don't have to insert the entire script once or even multiple times
To define a function, use function
followed by whatever name you choose. Then, in parentheses, specify which parameters are to be used. These are separated by commas.
parameterName : parameterType
To create a function without parameters, insert empty parentheses ()
.
Like scripts, the last line in the definition of the function is the return value.
To use your functions across the entire database, enter the function in the tab bar of the database under Options in Global functions.
Options are displayed when you're in edit mode .
Enable edit mode
Click the Options tab
Enter your function(s) under Global Functions.
Insert the function in a formula field of a table and that function is only available in that formula field. This is useful when keeping repetitive sections short, or when your function refers to the current table, respectively.
Let's create a function hello
to greet a person and tell them their age. First, pass the function a string for the name and a number for the age as parameters. These parameters are inserted into a given sentence at the appropriate positions.
Result: Hello Mom. You are 100 years old!
If you called the function like this: hello("Mom", 100)
Unfortunately, not all data types are currently supported by user-defined functions.
These following data types are already available for creating user-defined functions.
if ... then ... else if | switch ... case
Create multiple conditional statements by concatenating if-then-else blocks. Write another if
after else
for another condition and so on—continue for as long as needed.
As in the previous example, use the Total number field again and insert the following script into a Formula field:
Result: In the function field you will receive the response "Cash"
, "Card"
, or "Please enter an amount!"
according to the input.
Replace multiple nested conditional statements with switch ... case
. Use this statement to query an expression (switch ...
) for possible results (case ...:
) and set a default behavior (default:
) if the expression does not correspond to any of the results.
Depending on the result, assign the next step accordingly. This helps avoid deeply nested if statements.
Tip: switch ... case
works best when the queried value is a choice field.
There's a choice field Payment method with the following options:
Cash
Bank transfer
Direct debit
Insert the following script into a formula field to display info about the selected payment type:
Result: Based on your entry in the Payment method choice field, exactly one of the following info is visible in your formula field:
Payment method: Cash
Payment method: Bank transfer. Only from €30.
Payment method: Direct debit. Do not forget your signature.
Please select a payment method.
Do you want to dive deeper into the if ... then ... else
topic? Take a look at the corresponding part of our video tutorial.
Do you want to dive deeper into the switch
topic? Take a look at the corresponding part of our video tutorial.
If the condition is not set to false
on any of the passes, there's a risk of ending up in an infinite loop, causing Ninox to explode.
Result: Aaron, beate, conrad, Dahlia, Eddi, Fatima
Given the amount of data that needs to be processed and the related processing time (performance), we recommend using ...where
since it's faster.
Click on the gear icon erscheint, then choose Edit fields (2) to modify table settings.
This prevents subsequent transactions from getting blocked and boosts performance.
parameterName | parameterType |
---|---|
Data type | Description | Example |
---|---|---|
name
text
age
number
text
corresponds to the data type string
and stands for simple text
"Mom"
number
is a number
100
boolean
is either true or false
date
is a date
date(1922, 1, 13)
time
is a time
time()
datetime
corresponds to the data type timestamp
and stands for a timestamp
datetime(date(1922, 1, 13), time())
Table name
corresponds to a record from the specified table
myRecord : 'Table 1'
=
equal
1 + 1 = 3 - 1
Apples = Pears
!=
not equal
Apples != Pears
1 + 1 != 3 - 1
<
less than
4 * 2 < 10
10 < 4 * 2
<=
less than or equal to
5 * 2 <= 10
10 <= 4 * 2
>
greater than
10 > 4 * 2
4 * 2 > 10
>=
greater than or equal to
5 * 2 >= 10
4 * 2 >= 10
like
contains
"Hello" like "el"
"el" like "Hello"
"Mom" = "Mom"
"Mom" = "Dad"