It is often useful to adhere to a code/script style guideline to help make your scripts clean, clear and easily readable. This is especially helpful for when you go to revisit an old script in the future, or for sharing the scripts that you author with others.

This page describes some scripting tips and syntax guidelines which were used in creating the Sweet for ArcGIS built-in examples that are available in the Script Editor.

If you’re looking for more information on Arcade guidelines, then take a look at the Arcade Structure and Logic page on the Esri Developer website.

Script examples are available for most contexts where a script can be used to customise or configure behaviour. To access these built-in script examples, launch the Script Editor and click on the Examples tab.

Variables must be declared before use with the var keyword. They may be assigned any valid type, and can be re-assigned new values of a different type.

Declaring variables

var x = 10;
return x ; // returns 10

x = "hello";
return x; // returns "hello"

Variable Names:

A variable name should be self-descriptive. It shouldn’t be necessary to add a comment for additional documentation to the variable.

Use camelCase for variable names. For example use:

// use:
var myVariableName = true;
// instead of:
var myvariablename = false;

Semicolons

Semicolons should be included in Arcade scripts to avoid errors from multiline statements.

In general semicolons appear after returns, creating new variables, updating variables, continues, running functions, for example:

var i;                        // variable declaration
i = 5;                        // value assignment
i = i + 1;                    // value assignment
return true;                  // return
continue;
var lineFeature = FeatureSetByName($map, "Line");

var i = 0; i++               // <-- semi colon obligatory

Strings

Use double quotes ” ” for strings in Arcade scripts for example:

var fruits= [
    "Apple",
    "Banana",
    "Cranberries"
];

var classArray[0] = "Forest";

Some functions such as Filter() use a SQL expression as an input. In this case it is necessary to use single quotes within the expression string to prevent closing SQL Query Expression:

//Get Orange Trees in selection
var orangeTrees = Filter(
    FeatureSetByName($selection, "orchardtrees"), //FeatureSet
    "Fruit = 'Orange'" //SQL Query - single quotes around orange text string.
);

Dictionary objects

When declaring dictionary objects:

  • place the opening bracket on the same line as the object name.
  • use colon plus one space between each property and its value.
  • place the closing bracket on a new line, without leading spaces.
  • always end an object definition with a semicolon.
var person = {
  firstName: "John",
  lastName: "Doe",
  age: 50,
  eyeColor: "blue"
};

Short dictionary objects can be written compressed, on one line, using spaces only between properties, like this:

var person = {firstName:"John", lastName:"Doe"};

Adding comments

Follow some simple rules to adding comments into your scripts:

  • Keep comments as close to the code being described as possible. Comments that aren’t near their describing code are frustrating to the reader and easily missed when updates are made.
  • Don’t use complex formatting (such as tables or ASCII figures). Complex formatting leads to distracting content and can be difficult to maintain over time.
  • Don’t include redundant information. Assume the reader of the code has a basic understanding of programming principles and language syntax.
  • Design your code to comment itself. The easiest way to understand code is by reading it. When you design your code using clear, easy-to-understand concepts, the reader will be able to quickly conceptualize your intent.

Defining functions

Function placement:

User defined functions must be declared above the code that uses them, otherwise a runtime error will occur.

Function names

Use camelCase when defining your own functions. This distinguishes them from built-in functions
which use PascalCase (each word starts with a capital, and proceeding words also have a capital).

// User defined function - camelCase
function areaCheck(a) {... }

// Built-in function - PascalCase
FeatureSetByName(...)

Filters

Aim to have short concise filter SQL queries. If a filter requires a long SQL query of strings/integers, place these in an array first and then use IN @arrayname in the filter. For example:

var lineClasses = [
    "stream", 
    "gully", 
    "river"
];

var lineFilter = Filter(FeatureSetByName($map, "Line"), "classification IN @lineClasses");

FeatureSetByName

When using functions such as FeatureSetByName, calls to query a feature service are made. This can be quite intensive on the time it takes to run a script, especially if the call is repeated or multiple layers are involved. When developing a new script, it is advisable to monitor network traffic in your browser to see if requests are being made to the server. If so, it may be possible to remove these calls and for Arcade to to look at the layer locally.

// For example, using the following code makes a call to the server:
var lineFilter = Filter(FeatureSetByName($map, "Line"), "subtype = 'A Road'");

// but if you establish the FeatureSetByName as a variable first and then use
// the variable in the filter, the query is done locally:
var lineFeature = FeatureSetByName($map, "Line");
var lineFilter = Filter(lineFeature, "subtype = 'A Road'");

Structure and Logic

General

Curly braces should be used for all control structures (i.e. if, else, for, while), even if the body contains only a single statement. The first statement of a non-empty block must begin on its own line.

The opening curly brace should be placed on the same line as the corresponding keyword – not on a new line. There should also be a space before the opening bracket.

// Always follow if, else, for and while with a {} - block, e.g.:
if (someVeryLongCondition()) {
    doSomething();
}

// Vs.
if (someVeryLongCondition())
    doSomething();

For loop

Try to avoid nesting code too many levels deep.

When working with a for loop, use meaningful names for loop variables unless it is a simple counter variable such is i, j and k.

/* using variable name related to the array/feature set being looked at makes
*  it easier to read
*/
for (var line in lineFilter) {
    …
}

/*
* In simple cases use a counter such as i, j ,k.
*/

for (let i = 0; i < 9; i++) {...}

If statements

If/else statements should be collapsed as follows:

if () {
    return true;
} else {
    return false;
}

Comments in if/else or if/else if statements should go within the else instead of between them. This helps with readability.

if (trueOrFalse) {
    // statement is true.
} else {
    // Code run if the statement is false
}

Operators

Always put spaces around operators ( = + – * / ), and after commas:

var x = y + z;
var values = ["Volvo", "Saab", "Fiat"];

Code Tips

This section provides some helpful tips and tricks for writing scripts within the Sweet for ArcGIS Builder application.

Fail fast methodology

To increase code performance and improve code readability a fail fast coding methodology is recommended.

Fail fast code is when checks are performed before running the bulk of the logic so only code that fulfils all the criteria is run.

This will help improve performance of for loops and make if statements more readable.

E.g. Check for items that need further analysis. 99 of the 100 items are in perfect condition and do not need further checks. Use fail fast code to ignore these cases.

for (var index = 0; index < Count(featureObject); index++) { 
    if (featureObject[index] == passCriteria) { 
        continue; 
    } 

    *Run complex code* 
} 

A simple if statement has been used instead of if / else as the else option is to continue running the code. This way of using if else statements improves code readability.

Data variables

Scripts will often reference hardcoded data values, such as classifications (“Commercial”, “Residential”, “Agricultural”), (“A-road”, “B-road”) etc. in order to define different script logic.

In order to future proof the scripts it’s recommended that data values are defined at the beginning of the script and then are referenced by their variable name within the body of the script. This means that if a value needs to be changed it can be altered in just one location, instead of in many parts of the script.

//Avoid this style of referencing variables:
//***** Script Start *****/
var featureBoundaryType = $feature.boundarytype;
if (featureBoundaryType == "Brick wall" || featureBoundaryType == "wire fence" ||
    featureBoundaryType == "wooden fence" || featureBoundaryType == "electric fence") {
   return true;
}


//Instead use this style of referencing variables:
//***** Script Start *****/
var featureBoundaryType = $feature.boundarytype;
var validBoundaryTypes = ["Brick wall", "wire fence", "wooden fence", "electric fence"];

// use IndexOf to check whether the boundarytype in the featureBoundaryType array.
if (IndexOf(validBoundaryTypes, featureBoundaryType ) != -1) { 
   return false; 
}

Debugging Sweet Arcade

Using the Console() function in Arcade is a useful way of debugging your scripts. Each time the console function is called, the value of its argument is printed into the Web Browser’s developer console.

It is useful when developing and testing a script to log to the console variables being used. This allows you to check that the variables are being correctly populated and contain the data in the format that you expect.

The Test button within the Arcade Editor of the Builder can be used for testing the script within the script editing environment. These tests will quickly indicate any syntax errors which could cause the script to fail.

In some cases the script editor may indicate errors when a test is run in the builder but may actually succeed when running in an operational application environment. If after reviewing the script for syntax errors, the test still fails, it is recommended testing the arcade scripts operation in a running version of the application.

// *** Example Debugging
// In Sweet the result of this console will appear in the Dev tools (e.g. for Chrome press F12)
var variableFeature = FeatureSetByName($map, "Line");
var variableIntersect = Intersects(geometry($feature), variableFeature);
Console ("this feature intersects a line this many times: " + Count(variableIntersect);
// > Console tab > this feature intersects the line this many times: 1.
// In a map viewer, the consoles can be viewed in the Arcade editor when you click Test > Messages.

Checking for existence of a property or value

It is often useful to know whether a property exists within a dictionary object or whether a variable exists within an array.

HasKey() and IndexOf() are useful functions for performing these checks.

// Dictionary Objects
var nameDict = {
    firstname:"John",
    secondname: "Smith"
};

HasKey(nameDict, "age")
// >> returns false

// Arrays
var list = [1, 2, 3];
IndexOf(list, 3)
// returns zero-based index position
// >> returns 2

IndexOf(list, 10)
// value not in list
// >> returns -1

Iteration

For loops can iterate through arrays, dictionaries and FeatureSets. The type of the loop variable depends on the type of variable being iterated through.

Arrays

For loops iterate through an array using the index not the terms.

// *** Simple example - logging to Console index.
var list = ["apples", "bananas", "carrots"];

//this for loop logs to Console the index for each item in the list:
for (var i in list) {
    Console(i)
}

// This logs the following.
// >> 0
// >> 1
// >> 2

// *** To access a value associated with the index use accessor notation
// e.g. array[index]

//this for loop logs to Console the value for each item in the list:
for (var i in list) {
    Console(list[i])
}

// This logs the following:
// >> "apples"
// >> "bananas"
// >> "carrots"

// *** Adding items to a new Array
//
// In some cases you may wish to populate a new array based upon values from
// a different array:

// declare variables
var input = [5, 10, 15, 20];
var output = [];

for (var i in input) {
    output[i] = input[i] * 2; //produce a new array with each element doubled
}

Console(output)

// This logs the following:
// >> [10, 20, 30, 40]

Dictionaries

For loops may iterate through keys in a dictionary.

var myDictionary = Dictionary("field1", 1, "field2", 2);
//{field1: 1, field2: 2}
for (var field in myDictionary) {
    Console(field)
}

// This logs the following:
// >> "field1"
// >> "field2"

FeatureSets

For loops may iterate through items/features in a FeatureSet.

var buildings = FeatureSetByName($datastore, "Building_Footprints");

for (var features in buildings) {
    Console(features)
}

// This logs each feature in the FeatureSet.
// >> {"geometry":{...},"attributes":{...}}