Calculation rule to create new feature (copy selected feature)

732
8
Jump to solution
07-08-2022 10:55 AM
AndrewKan
New Contributor II

Hi,

I'm new to arcade and I'm trying to setup an immediate calculation rule where if the user updates the status to "replaced", the script will make a copy of the selected line feature with the same attributes and also update a field of the $feature.  I've got the update a field part working, but cannot seem to get the create new line feature with same attributes values going.  I'm not sure if i'm using the Dictionary and Feature functions properly. 

Some of the fields are read only as they may be used for editor tracking, etc.

Any help would be appreciated.  Thanks in advance!

 

if ($feature.Status =='REPLACED'){

  var attributes = Dictionary(Text($feature))["attributes"]

  Feature(Geometry($feature), attributes)
  return 2022
}
else {
  return -9999
}

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

You can absolutely create (and update or delete) features in the same table or even different tables using attribute rules. The trick is to not return a value, but a dictionary, using special dictionary keys: Attribute rule dictionary keywords—ArcGIS Pro | Documentation

 

For your case, the rule would look somewhat like this:

// calculation attribute rule
// triggers: (Insert,) Update
// Exclude from application evaluation!

// if status did not change to "REPLACED", return -9999
var status_changed_to_replaced = $feature.Status == "REPLACED" && $originalfeature.Status != "REPLACED"
if(!status_changed_to_replaced) { return -9999 }

// copy attributes
var copy_fields = ["Field1", "Field2", "Field3"]  // exclude readonly fields (OBJECTID, GlobalID, editor tracking, etc.)
var old_attributes = Dictionary(Text($feature)).attributes
var new_attributes = Dictionary()
for(var f in copy_fields) {
    var field = copy_fields[f]
    new_attributes[field] = old_attributes[field]
}
// optional: set attributes
new_attributes.Status = "AUTO_INSERTED"

// return the updated field value and instruct ArcGIS to create a new feature
return {
    "result": 2022,
    "edit": [{
        "className": "Database.DataOwner.Featureclass", // complete name of your feature class here (the same class as the one on which you create this rule)
        "adds": [{"geometry": Geometry($feature), "attributes": new_attributes}]
    }]
}

Have a great day!
Johannes

View solution in original post

8 Replies
RPGIS
by
Occasional Contributor III

Hi @AndrewKan,

 

There isn't any functionality for arcade to create a feature. If you are looking to create features for based on new inputs from the field, then the only way to do so would be to create a separate python script. You can then schedule a script to run via bat file and have windows task scheduler run it on a schedule. That is the only way, as far as I know, that would work for what you are trying to achieve.

0 Kudos
AndrewKan
New Contributor II

Hmm... that's too bad.  Thanks for the info.

I had thought that the Feature data function would be able to create new features, but I guess I misinterpreted it.

https://developers.arcgis.com/arcade/function-reference/data_functions/#feature

0 Kudos
JohannesLindner
MVP Frequent Contributor

You can absolutely create (and update or delete) features in the same table or even different tables using attribute rules. The trick is to not return a value, but a dictionary, using special dictionary keys: Attribute rule dictionary keywords—ArcGIS Pro | Documentation

 

For your case, the rule would look somewhat like this:

// calculation attribute rule
// triggers: (Insert,) Update
// Exclude from application evaluation!

// if status did not change to "REPLACED", return -9999
var status_changed_to_replaced = $feature.Status == "REPLACED" && $originalfeature.Status != "REPLACED"
if(!status_changed_to_replaced) { return -9999 }

// copy attributes
var copy_fields = ["Field1", "Field2", "Field3"]  // exclude readonly fields (OBJECTID, GlobalID, editor tracking, etc.)
var old_attributes = Dictionary(Text($feature)).attributes
var new_attributes = Dictionary()
for(var f in copy_fields) {
    var field = copy_fields[f]
    new_attributes[field] = old_attributes[field]
}
// optional: set attributes
new_attributes.Status = "AUTO_INSERTED"

// return the updated field value and instruct ArcGIS to create a new feature
return {
    "result": 2022,
    "edit": [{
        "className": "Database.DataOwner.Featureclass", // complete name of your feature class here (the same class as the one on which you create this rule)
        "adds": [{"geometry": Geometry($feature), "attributes": new_attributes}]
    }]
}

Have a great day!
Johannes
AndrewKan
New Contributor II

Thanks so much Johannes.  I had lost hope.  I'll give this a try and will report back.

Thank you!!

0 Kudos
BrianRosa
New Contributor

Hello Johannes,

I have been attempting this expression for a similar workflow but have been consistently running into a "Geometry cannot have Z values" error. The feature class I am copying from is Z-enabled while the feature class I am copying to is not. Do you know how I can resolve this issue? Thank you!

0 Kudos
AndrewKan
New Contributor II

Hi @JohannesLindner,

This works great.  I was wondering tho if you can help me make a couple enhancements. 

Since I wanted to use this attribute rule for multiple feature classes I'm trying to figure out how to extract the feature class associated with the $feature instead of hardcoding it. 

Also, if possible it would be nice if I didn't have to hardcode the fields to copy since there are quite a few fields and if there's a schema change then I'd have to update the attribute rule also.  Ideally, it would be able to extract all the non-readonly fields and dump them into the copy_fields variable.

Thank you so much for your help thus far.  You're awesome. 

0 Kudos
JohannesLindner
MVP Frequent Contributor

I'm trying to figure out how to extract the feature class associated with the $feature instead of hardcoding it.

AFAIK, that's not possible. You'll have to hardcode that.

 

Ideally, it would be able to extract all the non-readonly fields and dump them into the copy_fields variable.

That does sound like a better way... You'll have to hardcode the readonly fields, but they should be the same for all feature classes, so you only have to do it once. The list in the code is not complete!

var readonly_fields = ["OBJECTID", "GlobalID", "Shape__Area", "Shape__Length", "created_by", "created_on", "GDB_ARCHIVE_OID", "GDB_IS_DELETE"]  // exclude readonly fields (OBJECTID, GlobalID, editor tracking, versioning, etc.)
var old_attributes = Dictionary(Text($feature)).attributes
var new_attributes = Dictionary()
for(var field in old_attributes) {
    if(!Includes(readonly_fields, field)) {
        new_attributes[field] = old_attributes[field]
    }
}

Have a great day!
Johannes
AndrewKan
New Contributor II

This works great!  Thanks again for all your help.

Cheers

0 Kudos