With the following attribute rule
var fsPoly = Intersects(fsPolyBoundary, Geometry($feature)) var loc = First (fsPoly) var name = """" if (loc == null) return {""errorMessage"": ""Transformers must be created in a substation.""} else name = loc.LOC_NAME return name + "" - "" + $feature.LOC_NAME;",,,False,True,False,,,,"{""type"":""PropertySet"",""propertySetItems"":[]}"
We can update a field name based on its relationship "within" another polygon.
If I want the field calculated on insert or edit, I do this:
Problem is, what if the user makes an attribute edit, not a shape edit? The rule still fires (and takes a performance hit).
With SQL triggers, I can restrict them to only fire if the shape is new or updated, and ignore any attribute updates.
The same functionality should exist for attribute rules.
Here some code I did that might help you. I have a function (AttributeHasChangedExcept) that check if any attribute has changed except those pass in the array (you could have an empty array if you want).
I think in your case the array would be empty, meaning the if the rule was triggered it is because of a geometry change...in that case you could do the rest of your code...maybe it is not exactly what you need but it could be adapted
//check if a value is in the array case insentitive
function IsValInArray(val, array){
for (var i in array){
if (upper(val)== upper(array[i])){
return true
}
}
return false
}
//check if attribute of feature are the same of previous
//Except the one in the ignore array
function AttributeHasChangedExcept(attrIgnore){
//get and transform all attribute to dictionary
var dictCurrent = Dictionary(text($feature))["attributes"]
var hasChanged = [false,""]
//Search each attribute to see if value was changed
for (var attr in dictCurrent){
//if not in the ignoreed attribute
if (!IsValInArray(attr, attrIgnore)){
var curVal = $feature[attr]
var prevVal = $originalFeature[attr]
if (curVal != prevVal){
hasChanged = [true,attr]
}
}
}
return hasChanged
}
//Subord Assign cannot be updated except for:
// - Segment_ID
// - Set to Historical
// - Geometry (move)
//If original was SUBORD Assigned
if ($originalFeature.ADDRTYPE == "SUBORD" && $originalFeature.ADDRSTATUS == "AS"){
var ignoredAttribute = ["RD_SEGMENT_ID", "ROAD_NAME_ID", "ADDRTYPE", "SUBTYPE", "CREATE_BY", "CREATE_DATE", "MODIFIED_BY", "MODIFIED_DATE", "OBJECTID", "GLOBALID"]
//Filter 1 : check if attributes have changed
var check = AttributeHasChangedExcept(ignoredAttribute)
if (check[0]){
//They cannot be changed
return {"errorMessage":"Subord Assigned cannot be updated except for segment_id, Historical or point moved :" + check[1] + " has changed"}
}
//Filter 2 : New Address Type can only be Subord or Hist --> error
if (! ($feature.ADDRTYPE == "SUBORD" || $feature.ADDRTYPE == "HIST")){
return {"errorMessage":"Subord Assigned cannot be updated except for segment_id, Historical or point moved : point must be Subord or Historical"}
}
//we don't check geometry because change is allowed
return true
}
//If not the rule does not apply to this case
return true
I make use of "$originalFeature" to check if the area of the geomery has changed. If not, I skip the calculation and return the original value. However, the rule still fires, so I'm not sure if this helps performance.
// Calculate attribute "AREA" if geometry changes
var origGeometry = $originalFeature['Shape.STArea()'];
var newGeometry = $feature['Shape.STArea()'];
if (origGeometry != newGeometry){
return Round(Area($feature, 'square-meters'),0)
} else {
return $feature.AREA
}
Migrated from a duplicate idea:
I have calculation attribute rules that only needs to be run if the geometry is edited.
Example:
It's not necessary to run those kinds of calculation attribute rules if only the non-spatial fields get edited. And there are scenarios where unnecessarily running the attribute rules causes slow performance.
Could an optional setting be added to calculation attribute rules that would let us only run the rule if the geometry has been changed?
This would be wonderful for the datasets that need to have a date field for the last geometry update - but if those don't happen often, to auto fill, since it will most likely be forgotten! But this workflow won't work right now since attribute changes can trigger it too.
You should be able to do something like this:
// calculation attribute rule
// field: LastGeometryEdit (Date)
// triggers: Insert, Update
// geometry changed if we're inserting a new feature or if the old and new geometry aren't equal
var geometry_changed = $editcontext.editType == "INSERT" || !Equals(Geometry($originalfeature), Geometry($feature))
// if geometry changed, return current dtae and time, else return field value
return IIf(geometry_changed, Now(), $feature.LastGeometryEdit)
This could also be somewhat used as workaround for the original idea. But of course, the rule will still fire if you edit an attribute, so there will be some perfomance hit, especially if you edit large chunks at once.
var geometry_changed = $editcontext.editType == "INSERT" || !Equals(Geometry($originalfeature), Geometry($feature))
// no geometry edit? return the current field value
if(!geometry_changed) { return $feature.WATERSHED }
// your code (this will only get executed if geometry_changed is true)
var fsPolyBoundary = ...
var fsPoly = ...
var loc = ...
...
...
return name
Would love to have this built in as one of the check boxes. I have a lot of rules and don't want to have to copy this code into each one. It's also not a great solution since the rule fires anyways.
Tossing my vote in here for this as well. I'm trying to create a QAQC layer for our parcel fabric. I have an attribute that is acting as an error flag where if the stated area and calculated area are not within 10% of each other, it is flagged for review. In some instances, it can be redrawn and corrected, but in others, there may not be a better plat available, so the flag is cleared since it can't be improved. But with the way attribute rules currently work, if that parcel gets an attribute update, then it would add that error flag back since the it was technically updated even though the geometry didn't change.
This is now possible with Pro 3.4 (You can test it with the Beta 1) with Attribute Rules Triggering Fields
In previous releases of Pro, updating any field on a class that has immediate attribute rules will always execute update-based attribute rules enabled on that class. With this new feature in 3.4 Beta 1, users can specify what fields would trigger a constraint or immediate calculation rule on update, this way updating fields that do not affect the execution of attribute rules won't trigger the rules, significantly improving editing performance.
To solve this particular idea, one would remove all triggering fields (which is the default) from the rule and only keep the "Shape" as single triggering field. Updating any attribute won't execute the rule, only updating the geometry will.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.