Trigger
Overview
A Trigger automates business logics before/after a record creation/update/deletion. For example, a Trigger can automatically set a record’s field to a particular value, after you make a certain change on that record.
It runs on the server side, has access to the current record being created/updated/delete and access to classes and functions within Script Libraries.
Javascript knowledge is required
Creating a trigger
Field name | Field type | Description | Example |
|---|---|---|---|
Trigger name | String | Name of the Trigger | Incident - Location based on Requested for location |
Table | Reference | Records on this table will run this Trigger | Incident |
Field | Reference | If nominated, the field here have to change before the Trigger runs |
|
Description | Text | For administrative purposes, provide information what Trigger is about | Set an Incident’s Location based on Requested for’s Location if it isn’t set yet. |
Active | Boolean | If active, run the Trigger | Yes |
Trigger when? | Choice | Before: Runs the Trigger before the record is saved into the database. ℹ️ Before is recommended if your business logic is to modify/enforce some of the current record’s fields. Doing those prior to writing into the database will save the number of database transactions. In other words, you can set values without writing current.update(). ⚠️ Do not update the current record in a before trigger (i.e. do not include current.update()); After: Runs the Trigger after the record is saved into the database ℹ️ After is recommended if your business logic is to create/update/delete records on other Tables or make API calls, etc as you want the changes for the current table to be written into the database first. Async: Runs the Trigger asynchronously and not sequentially/directly after a record is saved into the database | Before |
On transition(s) | Multiple reference | Workflow transition(s) off the Table’s Workflow |
|
On create | Boolean | If set to Yes, the Trigger will run when the record is about to be created | Checked |
On update | Boolean | If set to Yes, the Trigger will run when the record is about to be updated | Checked |
On delete | Boolean | If set to Yes, the Trigger will run when the record is about to be deleted | Unchecked |
Order | Integer | Determines the order of when this Trigger should run relative to other Triggers for the same Table that match the same conditions (Trigger when? On transitions(s), On create, On update and On delete). The lower the Order results in the Trigger to run earlier. This will mean if you reference a field that is set of a trigger that runs earlier than another one, you can access the changed script in the later trigger. | 20 |
Stop on exception | Boolean | If set to Yes and this Trigger hits an exception/error, then other Triggers that are supposed to run after this one, will not run. If this Trigger runs on Before and it hits an exception, all Triggers running on After will not run either. Example of exception includes if you have syntax issue or you are trying to access a non existent field or relationship of a table. | No |
Overrides | Reference | If this Trigger is to override specific Triggers running on the Table’s parent table. When set, the Trigger nominated in this field will not run. |
|
Script | Script | The Script you want run to automate business logic of your choice.
⚠️ Updating current record’s fields here does NOT require a current.update() IF the Trigger runs “Before” as the record creation/update hasn’t been written into the database yet. Including it will potentially cause a recursive trigger call. | if (!current.Location.hasValue() && current.RequestedFor.hasValue()) {
current.Location(current.RequestedFor().Location.value());
} Please refer to the Examples section below for other examples/use cases. This primarily uses the Table API (Server)Table API andUser Object (Client and Server) User Object (Server side only). |
Examples
The following is aimed to give some general examples of what Triggers can be used for/can do. You may also look at out of box Triggers for reference such as the ones for Incident management or Request management.
Auto assign an Incident to a user that progresses it from New to Work in Progress
Field name | Value |
|---|---|
Table | Incident |
Trigger when? | Before |
On transition(s) | *Whatever it is to transition workflow status from New to Work in Progress. Refer to Workflow |
On create | False (Unchecked) |
On update | True (Checked) |
On delete | False (Unchecked) |
Script | Example Below |
// set the group (either one of the user's groups or the currently assigned group if the user is a member of it)
let groupToAssign = "";
let currentGroup = current.AssignmentGroup.value();
let aGroupRec = Table("Group")
.AND(
EQUAL("Selectable", true),
OR(
SUBQUERY(
"AccessibleFrom",
IN("Table", ["Incident"])
),
NOT(
SUBQUERY(
"AccessibleFrom"
)
)
),
SUBQUERY(
"Member",
EQUAL("ID", user.getID())
)
)
.query();
while (aGroupRec.next()) {
let currentGroupID = aGroupRec.getID();
if (currentGroupID == currentGroup) {
groupToAssign = currentGroupID;
break;
} else if (groupToAssign == "") {
groupToAssign = currentGroupID;
}
}
if (groupToAssign != "") {
current.AssignmentGroup(groupToAssign);
}
// finally set the assignee
current.Assignee(user.getID());On creation or update of a User account, synchronise to the Conversation user account table, for Whatsapp Sofi chat purposes
Field name | Value |
|---|---|
Table | User |
Trigger when? | After |
On create | True (Checked) |
On update | True (Checked) |
On delete | False (Unchecked) |
Script | Example Below |
// If user's mobile number has changed
if (current.Mobile.hasChanged() && current.Mobile.hasValue() && current.Active() && !current.LockedOut()) {
let number = current.Mobile();
if (number.startsWith("+")) { // Whatsapp doesn't like +
number = number.replace("+", "");
}
let cuaRec = Table("ConversationUserAccount")
.EQUAL("User", current.getID())
.query();
if (cuaRec.next()) {
// if there is already a conversation user account for the user, update it
cuaRec.ExternalID(number);
cuaRec.ExternalDisplayName(current.displayValue());
cuaRec.update();
} else {
// if there isn't already a conversation user account for the user, create it
cuaRec = Table("ConversationUserAccount").newRecord();
cuaRec.ExternalID(number);
cuaRec.User(current.getID());
cuaRec.ExternalDisplayName(current.displayValue());
cuaRec.create();
}
} else if (current.Mobile.hasValue() && ((current.Active.hasChanged() && current.Active() && !current.LockedOut()) || (current.Active() && current.LockedOut.hasChanged() && !current.LockedOut()))) {
// if user's mobile number hasn't changed but user has been re-activated
let number = current.Mobile();
if (number.startsWith("+")) { // Whatsapp doesn't like +
number = number.replace("+", "");
}
let cuaRec = Table("ConversationUserAccount")
.EQUAL("User", current.getID())
.query();
if (!cuaRec.next()) {
cuaRec = Table("ConversationUserAccount").newRecord();
cuaRec.ExternalID(number);
cuaRec.User(current.getID());
cuaRec.ExternalDisplayName(current.displayValue())
cuaRec.create();
}
} else if ((current.Active.hasChanged() && !current.Active()) || (current.LockedOut.hasChanged() && current.LockedOut())) {
// if user is deactivated or locked out, delete the conversation user account record
let cuaRec = Table("ConversationUserAccount")
.EQUAL("User", current.getID())
.query();
if (cuaRec.next()) {
cuaRec.delete();
}
}Make an API call to synchronise an Incident across to another ticketing system, using ThirdPartyReference field that captures the other system’s Ticket ID
This requires the use of a Script Library. In this example, we would need one created called “IncidentIntegrationUtil” that has a function called “synchToOtherSystem”.
Creating code to make outbound HTTP API calls, you can refer to Outbound HTTP requests (Scripted)
Field name | Value |
|---|---|
Table | Incident |
Trigger when? | After |
On create | True (Checked) |
On update | True (Checked) |
On delete | False (Unchecked) |
Script | Example Below |
if (current.ThirdPartyReference.hasValue()) {
// if this ticket is already linked to another system's ticket
// NOTE: for this example, we are assuming here that we have a Script Library called "IncidentIntegrationUtil" that packages the API payload and send across to the other system
let returnMessage = IncidentIntegrationUtil.synchToOtherSystem("update", current);
current.WorkJournal(returnMessage);
current.disableTriggers(); // we do not want to cause a loop by running other Triggers as we only want to write to the Work Journal
current.update();
} else {
// if this ticket is not linked to another system's ticket yet
// NOTE: for this example, we are assuming here that we have a Script Library called "IncidentIntegrationUtil" that packages the API payload and send across to the other system
let returnMessage = IncidentIntegrationUtil.synchToOtherSystem("create", current);
current.WorkJournal(returnMessage);
current.disableTriggers(); // we do not want to cause a loop by running other Triggers as we only want to write to the Work Journal
current.update();
}