Attribute rule script expression examples

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

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 to get the next sequence value and persists this in the assetID field.

To create a sequence to reference in an attribute rule, use the Create Database Sequence tool. When using sequences in the script expression, ensure that the Exclude from application evaluation option is set to true.

return "Tx-" + NextSequenceValue ("assetid")

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 executes on 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 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 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 by 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's geometry are modified to be 5 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

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 in which you want to the constraint attribute rule to return a different error messages depending on the condition. The following is an example when a custom error is returned if the name or the installationDate 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 getting deleted with a constraint rule.

This constraint attribute rule prevents a feature from getting deleted unless the lifecyclestatus field is set to retired. If the lifecyclestatus doesn't equal retired, a custom error message is returned and edit fails. The rule is created to be triggered with 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 your rule. This is an example of substations that exceed the maximum kva 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 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 if a specific attribute value has changed.

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

Arcade syntax example using $originalfeature to check if 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 check if 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 check if 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 event triggering events enabled, but add conditions based on the type of edit.

Arcade syntax example using $editcontext to check 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
}