arcade

AMD: require(["esri/arcade"], (arcade) => { /* code goes here */ });
ESM: import * as arcade from "@arcgis/core/arcade";
Object: esri/arcade
Since: ArcGIS API for JavaScript 4.24

This module allows you to evaluate Arcade expressions outside traditional ArcGIS Arcade profiles. Profiles define the valid input variables (i.e. profile variables) for expressions, supported functions, and valid return types of expressions. All Arcade expressions executed in the ArcGIS API for JavaScript must conform to the rules of the profile where they are written. The createArcadeExecutor method provides an API for executing Arcade expressions outside the context of predefined ArcGIS Arcade profiles.

This module allows you to do the following:

  • Execute expressions already written for existing ArcGIS profiles in another context. For example, an end user may have written an expression for a renderer, popup, or label in a WebMap and the data produced by the expression should be displayed outside the WebMap in a custom component, table, or summarized in a chart.
  • Define custom Arcade profiles and provide a configurable experience within an app for users to write their own expressions.
  • Developers may want to take advantage of the simplified experience of filtering and querying data using the chainable FeatureSet functions Arcade provides.

Method Overview

Name Return Type Summary Object
Promise<ArcadeExecutor>

Compiles an Arcade expression and its profile into an executor.

more details
arcade
Profile

Creates a Profile definition for an Arcade profile implemented in the ArcGIS API for JavaScript.

more details
arcade

Method Details

createArcadeExecutor(script, profile){Promise<ArcadeExecutor>}

Compiles an Arcade expression and its profile into an executor. The executor provides functions to evaluate the results for profile variables.

Parameters
script String

The Arcade expression to compile and execute.

profile Profile

The profile definition used to execute the given expression. The profile defines the profile variable names and data types the user may use as inputs in the expression. The variable instances are provided to the executor function.

Returns
Type Description
Promise<ArcadeExecutor> Resolves to an ArcadeExecutor that provides a synchronous (if applicable) and asynchronous function used to evaluate the compiled Arcade expression when provided with valid input profile variables.
See also
Examples
// Synchronous execution for all features in layer view
// % of the population not in labor force
const arcadeScript = "(($feature.POP_16UP - $feature.EMP_CY) / $feature.POP_16UP) * 100"

const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }]
};

const laborForceExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = laborForceExecutor.fieldsUsed;

const { features } = await layerView.queryFeatures();

const allValues = features.map( (feature) => {
  return laborForceExecutor.execute({
    "$feature": feature
  });
});

// allValues can be displayed in a chart, or used to
// report stats for this variable
// Asynchronous execution for one feature clicked in the view

const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }, {
    name: "$layer",
    type: "featureSet"
  }]
};

// This expression executes on each feature click. It compares the % of the population
// not participating in the labor force with the same value of all features within
// one mile of the selected feature's location
const arcadeScript = `
  var featureNotLaborForce = Round((($feature.POP_16UP - $feature.EMP_CY)/$feature.POP_16UP)*100);
  var id = $feature.OBJECTID;

  var neighbors = Filter( Intersects( $layer, BufferGeodetic($feature, 1, "mile") ), "OBJECTID <> @id" );
  if( Count(neighbors) == 0 ){
    return "No neighbors within 1 mile";
  }

  var neighborsNotLaborForceAverage = Average(neighbors, "( (POP_16UP - EMP_CY) / POP_16UP) * 100");
  var difference = Round(featureNotLaborForce - neighborsNotLaborForceAverage);
  var differenceText = IIF(difference > 0, "+"+difference, Text(difference));
  return differenceText;
`;

const neighborhoodExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = neighborhoodExecutor.fieldsUsed;

view.on("click", async (event) => {
  const hitResponse = await view.hitTest(event, include: { layer });
  const hitGraphic = hitResponse?.results[0].graphic;

  const scriptResult = await neighborhoodExecutor.executeAsync({
    "$feature": hitGraphic,
    "$layer": hitGraphic.layer
  }, {
    spatialReference: view.spatialReference
  });

  // display the value of scriptResult in a UI component or use it
  // in some form of client-side analysis
});
createArcadeProfile(profileName){Profile}
Since: ArcGIS API for JavaScript 4.25

Creates a Profile definition for an Arcade profile implemented in the ArcGIS API for JavaScript. The result of this should be provided to the createArcadeExecutor method.

Parameter
profileName String

The name of the Arcade profile definition to create.

Possible Values:"constraint"|"feature-z"|"field-calculation"|"form-calculation"|"labeling"|"popup"|"popup-element"|"feature-reduction-popup"|"feature-reduction-popup-element"|"visualization"

Returns
Type Description
Profile Returns the profile definition used to execute an expression with the ArcadeExecutor.
See also
Example
const labelingProfile = arcade.createArcadeProfile("labeling");
// creates the following object to be provided to the createArcadeExecutor method.
// {
//   variables: [{
//     name: "$feature",
//     type: "feature"
//   }]
// }

const labelExecutor = await createArcadeExecutor("$feature.NAME + ' COUNTY'", labelingProfile);

Type Definitions

ArcadeExecutor

An executor provides a synchronous (if applicable) and asynchronous function used to evaluate the compiled Arcade expression with the inputs of the declared profile variables. It also provides metadata about the compilation result.

Properties
execute ExecuteFunction

A function that can be invoked to evaluate the compiled expression for a set of profile variables. Will return the results of the evaluation. This function will only be available if isAsync is false.

executeAsync ExecuteFunctionAsync

Asynchronous function that evaluates the compiled expression. This function may always be used to evaluate the expression, but must be used if isAsync is true.

fieldsUsed String[]

References the names of fields used in the compiled expression when working with the $feature profile variable or functions that expect field names, such as Expects. Field names referenced here should be requested by the underlying layer or datastore. In JavaScript, this is typically done with layer.outFields.

geometryUsed Boolean

Indicates whether the expression accesses or uses a feature's geometry.

isAsync Boolean

Indicates whether the compiled expression accesses data using a FeatureSet function and therefore must be executed using the executeAsync function. If false, the expression may be executed with execute or executeAsync.

See also
Examples
// Synchronous execution for all features in layer view
// % of the population not in labor force
const arcadeScript = "(($feature.POP_16UP - $feature.EMP_CY) / $feature.POP_16UP) * 100"

const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }]
};

const laborForceExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = laborForceExecutor.fieldsUsed;

const { features } = await layerView.queryFeatures();

const allValues = features.map( (feature) => {
  return laborForceExecutor.execute({
    "$feature": feature
  });
});

// allValues can be displayed in a chart, or used to
// report stats for this variable
// Asynchronous execution for one feature clicked in the view

const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }, {
    name: "$layer",
    type: "featureSet"
  }]
};

// This expression executes on each feature click. It compares the % of the population
// not participating in the labor force with the same value of all features within
// one mile of the selected feature's location
const arcadeScript = `
  var featureNotLaborForce = Round((($feature.POP_16UP - $feature.EMP_CY)/$feature.POP_16UP)*100);
  var id = $feature.OBJECTID;

  var neighbors = Filter( Intersects( $layer, BufferGeodetic($feature, 1, "mile") ), "OBJECTID <> @id" );
  if( Count(neighbors) == 0 ){
    return "No neighbors within 1 mile";
  }

  var neighborsNotLaborForceAverage = Average(neighbors, "( (POP_16UP - EMP_CY) / POP_16UP) * 100");
  var difference = Round(featureNotLaborForce - neighborsNotLaborForceAverage);
  var differenceText = IIF(difference > 0, "+"+difference, Text(difference));
  return differenceText;
`;

const neighborhoodExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = neighborhoodExecutor.fieldsUsed;

view.on("click", async (event) => {
  const hitResponse = await view.hitTest(event, include: { layer });
  const hitGraphic = hitResponse?.results[0].graphic;

  const scriptResult = await neighborhoodExecutor.executeAsync({
    "$feature": hitGraphic,
    "$layer": hitGraphic.layer
  }, {
    spatialReference: view.spatialReference
  });

  // display the value of scriptResult in a UI component or use it
  // in some form of client-side analysis
});
const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }]
};

// Arcade expression defined by user...
const syncExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = syncExecutor.fieldsUsed;

// throw error if expression from user uses
// invalid functions that require async execution
if(syncExecutor.isAsync){
  throw new Error("Invalid expression. Expression should not use FeatureSet functions.");
}

const { features } = await layerView.queryFeatures();

const allValues = features.map( (feature) => {
  return syncExecutor.execute({
    "$feature": feature
  });
});

// allValues can be displayed in a chart, or used to
// report stats for this variable
ArrayElementType

The type definition of a profile variable of type array.

Properties
type String|String

The Arcade data type of the variable. See ProfileVariableInstanceType to see the mapping of Arcade types to JavaScript types.

Possible Values:"dictionary"|"feature"|"featureSet"|"featureSetCollection"|"geometry"|"number"|"text"|"date"|"boolean"

properties ProfileVariable[]
optional

Only applicable when type is dictionary. The type definitions of the dictionary's properties. The names of these properties should not begin with the $ character.

elementType ArrayElementType
optional

Only applicable when type is array. The type definition of the Array's items. Arcade arrays must be of a single type when used as an input profile variable. When indicating an elementType, you do not need to specify a name for the element.

ArrayVariable

The type definition for an Arcade array profile variable.

Properties
name String

The name of the profile variable. To follow Arcade's naming convention, this should start with the $ character unless this variable is nested in a DictionaryVariable.

type String

The Arcade data type of the variable. For ArrayVariable, the type is always array. The corresponding JavaScript type to an Arcade Array is an array following the specification defined in ProfileVariableInstanceType.

elementType ArrayElementType
optional

The type definition of the Array's items. Arcade arrays must be of a single type when used as an input profile variable. When indicating an elementType, you do not need to specify a name for the element.

Example
const profile = {
  variables: [{
    name: "$checkpoints",
    type: "array",
    elementType: {
      type: "feature"
    }
  }]
};
DictionaryVariable

The type definition for an Arcade dictionary profile variable.

Properties
name String

The name of the profile variable. To follow Arcade's naming convention, this should start with the $ character unless this variable is nested in another DictionaryVariable. See the example below.

type String

The Arcade data type of the variable. The corresponding JavaScript type to an Arcade Dictionary is a plain Object following the specification defined in ProfileVariableInstanceType.

The value is always "dictionary".

properties ProfileVariable[]
optional

The type definitions of the dictionary's properties. The names of these properties should not begin with the $ character.

Example
const profile = {
  variables: [{
    name: "$analysisParams",
    type: "dictionary",
    properties: [{
      name: "distance",
      type: "number"
    }, {
      name: "projectType",
      type: "text"
    }, {
      name: "includeBuffer",
      type: "boolean"
    }]
  }, {
     name: "$projectLocation",
     type: "feature"
  }]
};
ExecuteContext

The execution context of the Arcade expression.

Property
spatialReference SpatialReference
optional

The spatial reference used by geometries in geometry functions.

ExecuteFunction(profileVariableInstances, context){ResultType}

Executes the compiled Arcade expression synchronously with the given profile variable instances. This function may not be used if the expression accesses data using FeatureSet functions.

Parameters
profileVariableInstances Object

An object of key/value pairs where the key is the name of a ProfileVariable defined when creating the executor. The key's value must be of type ProfileVariableInstanceType.

context ExecuteContext
optional

The context with which to execute the expression.

Returns
Type Description
ResultType Returns the value of the evaluated expression.
Examples
// Synchronous execution for all features in layer view
// % of the population not in labor force
const arcadeScript = "(($feature.POP_16UP - $feature.EMP_CY) / $feature.POP_16UP) * 100"

const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }]
};

const laborForceExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = laborForceExecutor.fieldsUsed;

const { features } = await layerView.queryFeatures();

const allValues = features.map( (feature) => {
  return laborForceExecutor.execute({
    "$feature": feature
  });
});

// allValues can be displayed in a chart, or used to
// report stats for this variable
const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }]
};

// Arcade expression defined by user...
const syncExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = syncExecutor.fieldsUsed;

// throw error if expression from user uses invalid functions
if(syncExecutor.isAsync){
  throw new Error("Invalid expression. Expression should not use FeatureSet functions.");
}

const { features } = await layerView.queryFeatures();

const allValues = features.map( (feature) => {
  return syncExecutor.execute({
    "$feature": feature
  });
});

// allValues can be displayed in a chart, or used to
// report stats for this variable
ExecuteFunctionAsync(profileVariableInstances, context){Promise<ResultType>}

Executes the compiled Arcade expression asynchronously with the given profile variable instances.

Parameters
profileVariableInstances Object

An object of key/value pairs where the key is the name of a ProfileVariable defined when creating the executor, whose value must be of type ProfileVariableInstanceType.

context ExecuteContext
optional

The context with which to execute the expression.

Returns
Type Description
Promise<ResultType> Resolves to the value of the evaluated expression.
Example
// Asynchronous execution for one feature clicked in the view

const profile = {
  variables: [{
    name: "$feature",
    type: "feature"
  }, {
    name: "$layer",
    type: "featureSet"
  }]
};

// This expression executes on each feature click. It compares the % of the population
// not participating in the labor force with the same value of all features within
// one mile of the selected feature's location
const arcadeScript = `
  var featureNotLaborForce = Round((($feature.POP_16UP - $feature.EMP_CY)/$feature.POP_16UP)*100);
  var id = $feature.OBJECTID;

  var neighbors = Filter( Intersects( $layer, BufferGeodetic($feature, 1, "mile") ), "OBJECTID <> @id" );
  if( Count(neighbors) == 0 ){
    return "No neighbors within 1 mile";
  }

  var neighborsNotLaborForceAverage = Average(neighbors, "( (POP_16UP - EMP_CY) / POP_16UP) * 100");
  var difference = Round(featureNotLaborForce - neighborsNotLaborForceAverage);
  var differenceText = IIF(difference > 0, "+"+difference, Text(difference));
  return differenceText;
`;

const neighborhoodExecutor = await createArcadeExecutor(arcadeScript, profile);
// ensures data values from fields used in the expression are
// available when the expression executes.
layer.outFields = neighborhoodExecutor.fieldsUsed;

view.on("click", async (event) => {
  const hitResponse = await view.hitTest(event, include: { layer });
  const hitGraphic = hitResponse?.results[0].graphic;

  const scriptResult = await neighborhoodExecutor.executeAsync({
    "$feature": hitGraphic,
    "$layer": hitGraphic.layer
  }, {
    spatialReference: view.spatialReference
  });

  // display the value of scriptResult in a UI component or use it
  // in some form of client-side analysis
});
Profile

Defines the definitions of a profile's input variables. This consists of an array of objects specifying the name of each profile variable and its Arcade data type. All profile names must begin with the $ character.

Property
variables ProfileVariable[]

The Arcade type definitions for profile variables used as input to the compiled expression.

Example
const profile = {
  variables: [{
    name: "$mapClick",
    type: "geometry"
  }, {
    name: "$threshold",
    type: "number"
  }, {
    name: "$feature",
    type: "feature"
  }, {
    name: "$map",
    type: "featureSetCollection"
  }]
};

The type definition of a profile variable. See the individual profile variable types for more information and examples.

The JavaScript types that may be used as inputs to profile variables when evaluating compiled expressions with ExecuteFunction or ExecuteFunctionAsync. See the table below for the following mapping of JavaScript types that may be used to hydrate profile variables for corresponding Arcade data types.

Arcade type JS type Notes
Number Number
Text String
Date Date
Boolean Boolean
Dictionary Object An object with key/value pairs with keys defined by a DictionaryVariable whose values must be one of ProfileVariableInstanceType.
Array Array Arcade arrays are immutable and must be of a single ProfileVariableInstanceType.
Geometry Geometry
Feature Graphic
FeatureSet FeatureLayer | FeatureSet
FeatureSetCollection Map | String A string may be provided, pointing to the url of a Feature Service.

The JavaScript type of the result returned from the Arcade expression.

SimpleVariable

The type definition for a simple Arcade profile variable.

Properties
name String

The name of the profile variable. To follow Arcade's naming convention, this should start with the $ character unless this variable is nested in a DictionaryVariable.

type String

The Arcade data type of the variable. See ProfileVariableInstanceType to see the mapping of Arcade types to JavaScript types.

Possible Values:"feature"|"featureSet"|"featureSetCollection"|"geometry"|"number"|"text"|"date"|"boolean"

Example
const profile = {
  variables: [{
    name: "$mapClick",
    type: "geometry"
  }, {
    name: "$threshold",
    type: "number"
  }, {
    name: "$feature",
    type: "feature"
  }, {
    name: "$map",
    type: "featureSetCollection"
  }]
};

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.