Attribute rule script expression examples

The following are examples of script expressions for calculation, constraint, and validation attribute rules.

Refer to the specific Arcade profile for attribute rules to learn more about the usage, profile variables, return types, and more.

See the Esri GitHub repository for more Arcade script expression examples for attribute rules.

Calculation attribute rule examples

Constraint attribute rule examples

Validation attribute rule examples

Examples for all rule types

Calculation attribute rule examples

Generate an ID by incrementing a sequence.

An immediate calculation rule is created on the assetID field in the transformer feature class and is triggered on insert edit operations. When you create a transformer, the NextSequenceValue Arcade function queries the database for the next sequence value using the inputSequenceName of assetid_seq. The assetID field for inserted features is populated with the prefix "Tx-" and the returned sequence value.

To create a sequence to reference in an attribute rule, use the Create Database Sequence tool.

Script expression for using a sequence named assetid_seq in a file geodatabase:

 return "Tx-" + NextSequenceValue ('assetid_seq')

Script expression for using a sequence owned by the map user named assetid_seq in an enterprise geodatabase:

 return "Tx-" + NextSequenceValue ('map.assetid_seq')

When using sequences in the script expression, ensure that the Exclude from application evaluation option is set to true. For enterprise geodatabases, use the fully qualified name of the sequence in the script expression, for example, owner.sequencename.

Return a custom error message for a calculation rule.

There are some cases when you want a calculation rule to return a custom error message as a failure when a condition is not met. In this example, an immediate calculation rule is created to populate the (FacilityID) field based on the intersecting substation. The rule is triggered by insert and update operations. If you attempt to create a transformer in a substation, the Arcade expression fetches the name of the substation and uses the assetID value of the transformer to build the full FacilityID field (SubstationName-AssetID). If the transformer is created or moved outside of a substation, the script returns a custom error message using the errorMessage keyword.

//On Insert or Update, set FacilityID = SubstationName - AssetID use intersect to get the substation name
//If no substation (fail with error message dictionary,  must create in substation.) 
var fsStructureBoundary =  FeatureSetByName($datastore, "Substation", ["name"], true)
var fsSubstation = Intersects(fsStructureBoundary, Geometry($feature))
var substation = First (fsSubstation)

var subname  = ""
if (substation == null)
   return  {"errorMessage": "Transformers must be created in a substation."}
else 
   subname =  substation.name

return subname + " - " + $feature.assetid;

Mark another feature as requiring evaluation.

You can author a calculation rule that marks other features as requiring either calculation or validation. When performing a calculation, you can use the calculationRequired or validationRequired keyword in a dictionary to reset the Validation Status attribute for one or more features. This is useful when a feature class is dependent on another feature class. In this example, the assetID field in the Transformer feature class depends on the intersecting Substation feature class. A calculation rule is created on the yearName field of the Substation feature class. When the substation name is updated, the new name and the current year are stored in the yearName field. As part of this logic, all the transformers intersecting the substation in the Transformer feature class are marked as requiring calculation. There is a batch calculation rule on the Transformer class that calculates the Transformer assetID value the next time the rule is evaluated to reflect the new name and year of the substation.

//Updating the substation name marks its transformers as requiring calculation and updates the yearName to the new name and year. 
//To recalculate the facility id on all transformers, mark all associated transformers as requiring calculation.
var fsDevice =  FeatureSetByName($datastore, "Transformer", ["globalid"], false)
var fsDeviceIntersects = Intersects (fsDevice, Geometry($feature))

var transformers = [];
var count = 0;

for (var i in fsDeviceIntersects)
   transformers[count++] = i.globalid;
var newName = $feature.name + " " + Year(Now())
return {
   'result': newName, 
   'calculationRequired': 
       [
          {
              'className':"Transformer",
              'globalIDs': transformers
           }
       ]
   }

Edit another feature class with a calculation rule.

You can use attribute rules to perform inserts, updates, and deletes to another feature class using the edit dictionary keyword. The example below is a calculation rule on a text field of a district boundaries feature class. When editing a polygon in the district boundaries feature class, this attribute rule updates any intersecting address points with the district name.

var fsAddress = FeatureSetByName($datastore, "Address_pnts", ["globalid"], false)
var fsListAddpnts = Intersects(fsAddress, $feature)
var AddList = []
var counter = 0
var noAddress = Count(fsListAddpnts)
if (noAddress > 0) {
    for (var address in fsListAddpnts) {
        AddList[counter] = {
            'globalid': address.globalid,
            'attributes': {
                'add_district_name': $feature.DistrictName
            }
        }
        counter++
    }
    return {
        'result': noAddress + ' addresses found in the district.',
        'edit': [{
            'className': 'Address_pnts',
            'updates': AddList
        }]
    }
} else {
    return 'No address points in district.'
}

Edit the geometry of a feature with a calculation rule.

Create a calculation rule on the shape field of a dataset to make modifications to the geometry of a feature. In this script example, the point feature geometry is modified to be 5 metric units away from the first feature in pointClass1.

Caution:

The spatial reference of the returned geometry must match the spatial reference of the dataset containing the attribute rule.

//This calculation attribute rule is added to the shape field of a point feature class called pointClass2
var centerFeature = First(FeatureSetByName($datastore, "pointClass1"))
//Get the x and y values of the feature in the pointClass1
var x0 = Geometry(centerFeature).x
var y0 = Geometry(centerFeature).y
//Get the x and y values of the current feature in the pointClass2
var x1 = Geometry($feature).x;
var y1 = Geometry($feature).y;
var x2 = 0;
var y2 = 0;
var d = 5
//Calculate the Euclidean distance from feature in pointClass1 and current feature in pointClass2
var d1 = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0))

//Calculate the new x and y to be within 5 metric units while maintaining slope
x2 = (x1 - x0) * d / d1 + x0;
y2 = (y1 - y0) * d / d1 + y0;
//Create a point geometry from the new x and y values
var pointA = Point({
    "x": x2,
    "y": y2,
    "z": 0,
    "spatialReference": Geometry(centerFeature).spatialReference
});
return pointA

Read related records for a relationship class using the FeatureSetByName Arcade function.

A calculation rule is created on the InspectionCount field in the pole feature class that participates in a one-to-many relationship class with the inspection table. The FeatureSetByName function can be used to read the inspection class directly and retrieve the related records on update. Using this Arcade function requires knowledge of the relationship class field. For this relationship class, the origin primary key is the globalID field of the pole feature class and the origin foreign key is the poleguid of the inspection standalone table.

//A calculation rule that returns the count of a pole inspection records.
//When a pole feature is updated, the calculation rule reads all its related inspections records from the comments field and returns the total inspection count for that feature. 

Var fs = FeatureSetByName($datastore, “Inspection”, [“comments”], false)
Var poleGuid = $feature.poleguid 
Var fsinspected = Filter(fs, “POLEGUID= @poleguid”);
Return count(fsinspected)

Read a related record for a relationship class using the FeatureSetByRelationShipName Arcade function.

The same script to read related records for a relationship class can be rewritten with the FeatureSetRelationshipName function. Using this function, you don’t have to know the foreign key, only the relationship name, pole_inspection.

Caution:

When using this function to create an attribute rule, ensure that the Exclude from application evaluation option is set to true.

//A calculation rule that returns the count of a pole inspection records.
//When a pole feature is updated, the calculation rule reads all its related inspections records from the comments field and returns the total inspection count for that feature.

Var fsinspected = FeatureSetByRelationshipName($feature, “pole_inspection”, [“comments”], false)
Return count(fsinspected)

Read a related record for a relationship class using the FeatureSetByRelationshipClass Arcade function.

The same script to read related records from a relationship class can be rewritten with the FeatureSetByRelationshipClass function. Using this function, you don’t have to know the foreign key, only the relationship name, pole_inspection. This function supports execution for both server and client side, therefore attribute rules that use this function can be executed locally in the application.

//A calculation rule that returns the count of a pole inspection records.
//When a pole feature is updated, the calculation rule reads all its related inspections records from the comments field and returns the total inspection count for that feature.

Var fsinspected = FeatureSetByRelationshipClass ($feature, “pole_inspection”, [“comments”], false)
Return count(fsinspected)

Add a new related record for a relationship class on an update edit.

A calculation rule is used to create a new related record when a pole comment field is updated by the user. In this expression the edit dictionary keyword is used to create a new inspection record if the comments field changes. Similarly, you can update or delete related records. Refer to Attribute rule dictionary keywords for more information.

//A calculation rule that triggers on an update event when the pole comment field is edited. 
//The expression first checks if the comment field changed and creates a new related record.

If ($originalfeature.comment != $feature.comment)
{ 
    Return {
                 “edit”: [{
   “className”: “inspection”,
   “adds”: [{ “attributes”: { “comments”: $feature.comment } }] 
}] 

}
Return;

Constraint attribute rule examples

Return a Boolean value for a constraint rule.

This constraint attribute rule is created on the substation class and is set to trigger with insert and update operations. If the substation name is empty, the expression will return false and fail. If the substation name is not empty, the expression returns true and allows the edit to proceed.

if ($feature.name == null)
    return false;
else
    return true;

//another way of writing it
return !($feature.name == null)

Return a custom error message for a constraint rule.

There are some cases when you want the constraint attribute rule to return a different error message, depending on the condition. The following is an example when a custom error is returned if the name or the installationDate value for the substation is null.

if ($feature.name == null)
    return   {"errorMessage": "Substation must have a valid name."}
else if ($feature.installationDate == null)
    return   {"errorMessage": "Substation must have a valid installation date."}
else
    return true;

Prevent a feature from being deleted with a constraint rule.

This constraint attribute rule prevents a feature from being deleted unless the lifecyclestatus field is set to retired. If the lifecyclestatus value doesn't equal retired, a custom error message is returned and the edit fails. The rule is triggered by the delete operation.

if ($feature.lifecyclestatus == 'retired')
{
  return true;
}
return {'errorMessage': 'You are not allowed delete a feature until it is retired'};

Validation attribute rule examples

Return a Boolean value for a validation rule.

Validation rules are best for instances when you want to detect corrupt data, but you don't want to prevent editors from completing their work by using a constraint rule. You can evaluate rules and create errors for the features that violate the rule. This is an example of substations that exceed the maximum Kva value and are flagged as errors (polygon errors are created).

var fsTransformer =  FeatureSetByName($datastore, "L1Electric_Distribution_Device", ["objectid"], true)
var fsTransformerSubset = Intersects(fsTransformer, Geometry($feature))
var totalKva = 0;
for (var t in fsTransformerSubset)
    totalKva += t.kva

if (totalKva > $feature.maxKva)
     return false
else
     return true

The following example is a validation rule created on a poles feature class to ensure that when the structureheight value is 65 feet or greater, the material must be made of steel. An error feature is generated if this is not true.

if ($feature.structureheight >= 65)
{
    If (DomainName($feature, 'Material') == 'Steel')
    { return true; }
    else
    { return false; }
}
Else
{  return true; }

Examples for all rule types

Identify whether a specific attribute value has changed.

Use the $originalfeature variable to reference a feature's attributes before an edit is made. Compare $originalfeature and $feature using Arcade to determine whether a feature's attribute has changed.

Arcade syntax example using $originalfeature to determine whether an attribute has changed.

if ($feature.field == $originalfeature.field) {
    //code if field attribute hasn't changed
} else {
    //code if field attribute has changed.
}

Arcade syntax example using $originalfeature to determine whether geometry has changed.

if (Equals(Geometry($feature), Geometry($originalfeature))) {
    //code if geometry hasn't changed
} else {
    //code if geometry has changed
}

Arcade syntax example using $originalfeature to determine whether an attribute has changed by 50 percent.

if ($originalfeature.field == 0) {
    //code to avoid calculating change if $originalfeature.field was zero
} else {
    var percent_change = Abs(($feature.field - $originalfeature.field) / $originalfeature.field) * 100
    if (percent_change >= 50) {
        //code if percent change is by 50% or more
    } else {
        //code if percent change is less than 50%
    }
}

Identify the editing event trigger such as insert, update, or delete.

Use the $editcontext global variable to reference the edit type in Arcade logic. This allows you to create one attribute rule with all triggering events enabled, and add conditions based on the type of edit.

Arcade syntax example using $editcontext to determine the edit type.

if ($editContext.editType == "INSERT") {
    //code if the edit is an insert
} else if ($editContext.editType == "UPDATE") {
    //code if the edit is an update
} else if ($editContext.editType == "DELETE") {
    //code if the edit is a delete 
} else if ($editContext.editType == "NA") {
    //code when edit type is not applicable, for example batch calculation or validation rules
}