Hello, I am seeking a way in Arcade expression for Attribute Rules to add multiple features (parkA layer) intersected with an inserted or updated polygon feature (bufferA) to a third layer (NationalPark layer).
I managed to prepare an expression to add only a single feature intersected with a buffer polygon - please see the expression below. But I have not been able to find out the way for adding multiple features.
My final goal is to set up a batch calculation of Attribute Rules to achieve that, i.e. to add, update or delete all the features of NationalPark layer that correlated with each of buffer feature in one go. To start with, I tried set up an immediate calculation by the code but it only does for a single feature. Is there any way of selecting multiple features by the buffer and add them to the third layer?
Thanks in advance for any ideas!
// This rule is set in a bufferA (polygon)
// Target field :
// Insert and Update
// Exclude from app evaluation
// Decide an edit mode ("INSERT", or "UPDATE")
var mode = $editcontext.editType
// get parkA feature (polygon)
var parkA = FeatureSetByName($datastore, "parkA", ["*"], false)
var parkA_intersect = Intersects(parkA, Geometry($feature))
var parkA_first = First(fsparkA_firstIntersect)
// return error if $feature doesn't intersect any parkA polygon
if (parkA_first == null)
return {"errorMessage": "Buffer must be intersected with parkA polygon."}
// create the result dict
var result = {
"attributes": {
}
}
// initialize the edit arrays for adds and updates
var adds = []
var updates = []
if(mode == "INSERT") {
var add = {
"geometry": Geometry(parkA_first),
"attributes": {
"Status_A": parkA_first.statusA
}
}
Push(adds, add)
}
if(mode == "UPDATE") {
var update = {
"geometry": Geometry(parkA_first),
"attributes": {
"Status_A": parkA_first.statusA
}
}
Push(updates, update)
}
// return
return {
"result": result,
"edit": [
{
"className": "NationalPark",
"adds": adds,
"updates": updates
}
]
}
Instead of taking the First() feature of parkA_intersect, you need to loop through the featureset:
// get parkA feature (polygon)
var parkA = FeatureSetByName($datastore, "parkA", ["*"], false)
var parkA_intersect = Intersects(parkA, Geometry($feature))
// return error if $feature doesn't intersect any parkA polygon
if (Count(parkA_intersect) == 0)
return {"errorMessage": "Buffer must be intersected with parkA polygon."}
// create the result dict
var result = {
"attributes": {
}
}
// initialize the edit arrays for adds and updates
var adds = []
var updates = []
if(mode == "INSERT") {
for(var p in parkA_intersect) {
var add = {
"geometry": Geometry(p),
"attributes": {
"Status_A": p.statusA
}
}
Push(adds, add)
}
}
if(mode == "UPDATE") {
for(var p in parkA_intersect) {
var update = {
"objectID": p.OBJECTID,
"geometry": Geometry(p),
"attributes": {
"Status_A": p.statusA
}
}
Push(updates, update)
}
}
A note on the update objects: You need to specify which feature you want to update. You do that by supplying either the objectID or the globalID, see line 34 in the code above.
Attribute rule dictionary keywords—ArcGIS Pro | Documentation
Modified the code some
- Need to return the geometry in the FeatureSetByName, but if you are not changing the geometry of the intersected polygon, you do not need to return the geometry
- Do not call count on a FS if you are going to loop over it. The call to count causes a query to the layer with all fields, this can be expensive. Just use the loop to determine if there are any features
- I am not sure what you are trying to do on a insert vs an update. Has no affect on the intersected features. It sounds like you are trying to update the polygons with attributes from the point on top of it.
- List the fields you want from the polygon layer, no reason to return all the fields
- If you are not editing the $feature, you do not need to return a result
- I am a little confused on the outcome, so maybe the code changes below can you help
// get parkA feature (polygon)
var parkA = FeatureSetByName($datastore, "parkA", ["OBJECTID"], true)
var parkA_intersect = Intersects(parkA, Geometry($feature))
var updated_rows = []
var copied_rows = []
for(var p in parkA_intersect) {
var updated_row = {
"objectID":p.OBJECTID,
"attributes": {
"Status_A": $feature.statusA
}
}
}
Push(updated_rows, updated_row)
var copied_row = {
"geometry": Geometry(p),
"attributes": {
"Status_A": p.statusA
}
}
}
Push(copied_rows, copied_row)
}
if (Count(updated_rows) == 0){
return {"errorMessage": "Buffer must be intersected with parkA polygon."}
}
// return
return {
"edit": [
{
"className": "NationalPark",
"updates": updated_rows
},
{
"className": "CopiedClass",
"add": copied_rows
}
]
}
Hi Mike, thanks for your reply!
I tried the suggested code but unfortunately it came across an error, saying "Move failed, Failed to rotate related features [bufferA]A requested row object could not be located."
Update that I would like to do is, once the buffer is moved, then the originally intersected features of ParkA are deleted form NationalPark layer , and then the new intersected features of ParkA are added to NationalPark layer accroding to the new position of the buffer - please see pictures below.
I would like to set up the update function via batch calculation of attribute rules as a final goal - is this possible?
For example, insert a buffer and before move the buffer,
And then once buffer is moved, it should be like this
Hi Johannes, thanks for your reply!
Insert mode worked with the loop but for the update mode, it did not work unfortunately. Error came up, saying "Move failed, Failed to rotate related features [bufferA]A requested row object could not be located."
Update that I would like to do is, once the buffer is moved, then the originally intersected features of ParkA are deleted form NationalPark layer , and then the new intersected features of ParkA are added to NationalPark layer accroding to the new position of the buffer - please see pictures below.
I would like to set up the update function via batch calculation of attribute rules as a final goal - is this possible?
For example, insert a buffer and before move the buffer,
And then once buffer is moved, it should be like this