Select to view content in your preferred language

"Failed to Calculate Expression" using related tables in Field Maps?

264
4
Jump to solution
3 weeks ago
mseib13
New Contributor

Hi all!

I have a web map created to use in Field Maps for data collection and inspections of stormwater features. I used related tables with the parent "Inlets" and child "Inspections". I needed to copy the fields from the most recent child record to the parent record. Using the calculated expression below I was able to do so. I thought it was working great until I went to test in Field Maps and encountered "Failed to calculate expression" for all of the fields with the calculated value. It will not let me create a new parent feature because of this in mobile (the same alert appears in web but will let the feature be created and from there works fine). I've tried making those fields hidden but then get the error "5 hidden attributes failed" when submitting. At a loss for how to get this to work. Help please.

mseib13_0-1717078700547.png

mseib13_1-1717079466188.jpeg

 

 

0 Kudos
1 Solution

Accepted Solutions
JustinReynolds
Regular Contributor

There are a couple things to consider here now that you have this working for the most part.  

  • The behavior that you see with needing to go back to the parent feature and enter an edit session is by design.  Form calculations only execute in the context of a form edit session.  These expressions cannot be triggered externally from a child or any other feature.  If you happen to be using referenced data rather than hosted data, then you could consider Attribute Rules in addition to your Form Calculations to get the behavior you are seeking.  Attribute Rules happen 'Server Side' and triggers can be setup, while Form Calculations are happening 'Client Side' and are local to your current edit session.
  • ssuming your relationship is Simple (no orphaned children possible), then on INSERT we know there will never be any children to look for.  The way your expression is now, it is doing a lot work that is not necessary.  You should check the edit context first, then if it is "UPDATE" continue if not you should exit early by returning null.  This way there are no unnecessary calls to the server.

    It could look like the following; again I'll write in a way that use an implicit 'else'. Note this version will overwrite any existing values that may have already been calculated.

 

/* Checking Edit Context First, Return Null If INSERT or DELETE. */
if (Lower($editContext.editType) != 'update') { return null }; 

... The rest of your code goes here and only executes if the above condition is not met.​​

 


Note this version will NOT allow overwrites of existing values (it will only appear to calculate once). I chose one of the fields in your form, it would change for each field.

 

/* Checking Edit Context First, Return Null If INSERT or DELETE. */
if (Lower($editContext.editType) != 'update') { return null }; 

/* Checking if the current field already has a value. If so, return that value. */
if (!IsEmpty($feature.last_inspection_date)) { return $feature.last_inspection_date};

... The rest of your code goes here and only executes if the above conditions are not met.

 

 

var GID = $feature.GlobalID;
var sortedRecords = OrderBy(Filter(FeatureSetByName($datastore, "Inlet_Inspections"), 'GUID = @GID'), "Date");

... The rest of your code here.​

 

- Justin Reynolds, PE

View solution in original post

4 Replies
KenBuja
MVP Esteemed Contributor

There have been reports that the FeatureSetByRelationshipName function is buggy in Field Maps. The suggested workaround is to use FeatureSetByName and Filter the records using the key to get the related records.

JustinReynolds
Regular Contributor

Hello,

So when you create a new parent record we would expect no children to exist and you are seeking to return nulls in that case.  This might be a syntax issue in your code.  The mobile runtime for Field Maps is much more opinionated than that of the JavaScript API in my experience.  Map viewer will let you get away with a lot more than the mobile app and this lends itself to code that works when authoring and testing expressions that then don't work in Field Maps.

The following doesn't look like valid syntax (missing curly brackets), but the JavaScript API seems to know what you mean and either handles the bad syntax or was always hitting the else and therefore just skipping line 3.

 

...
if (count == 0)
return null
else {
  var inlet = first(relatedrecords)
  return inlet["Overall_Condition"]
}

 


Meanwhile, the mobile app doesn't like it as it is more opinionated. You may want to try with the code below.  Note: Because your 'if' statement has an explicit 'return' in it, you don't need the explicit 'else'.  The 'else' can be implicit here, as shown below.  I find the implicit 'else' to be much easier to read and use them whenever I can.

 

...
if (count == 0) { return null };

var inlet = First(relatedrecords);
return inlet['Overall_Condition'];

 

I hope this is all that it is.  If not, you may get some insight by looking at the troubleshooting logs in Field Maps, as it may give you the expression name and line number that caused the calculation error.

 

- Justin Reynolds, PE
mseib13
New Contributor

Thanks Justin, I combined your advice and Ken's- we're getting somewhere! Now I have solved the issue of the error in Field Maps (error still shows in web actually) but the fields don't calculate after I complete an inspection. It will only calculate if I go back into the parent feature to edit. Thoughts?

var GID = $feature.GlobalID;

var relrec = FeatureSetByName($datastore, "Inlet_Inspections");

var result = Filter(relrec, 'GUID = @GID');

var sortedRecords = OrderBy(result,"Date");

var cnt = Count(sortedrecords);

if (cnt == 0) {return null};

var inlet = First(sortedrecords);

return inlet['Overall_Condition']

0 Kudos
JustinReynolds
Regular Contributor

There are a couple things to consider here now that you have this working for the most part.  

  • The behavior that you see with needing to go back to the parent feature and enter an edit session is by design.  Form calculations only execute in the context of a form edit session.  These expressions cannot be triggered externally from a child or any other feature.  If you happen to be using referenced data rather than hosted data, then you could consider Attribute Rules in addition to your Form Calculations to get the behavior you are seeking.  Attribute Rules happen 'Server Side' and triggers can be setup, while Form Calculations are happening 'Client Side' and are local to your current edit session.
  • ssuming your relationship is Simple (no orphaned children possible), then on INSERT we know there will never be any children to look for.  The way your expression is now, it is doing a lot work that is not necessary.  You should check the edit context first, then if it is "UPDATE" continue if not you should exit early by returning null.  This way there are no unnecessary calls to the server.

    It could look like the following; again I'll write in a way that use an implicit 'else'. Note this version will overwrite any existing values that may have already been calculated.

 

/* Checking Edit Context First, Return Null If INSERT or DELETE. */
if (Lower($editContext.editType) != 'update') { return null }; 

... The rest of your code goes here and only executes if the above condition is not met.​​

 


Note this version will NOT allow overwrites of existing values (it will only appear to calculate once). I chose one of the fields in your form, it would change for each field.

 

/* Checking Edit Context First, Return Null If INSERT or DELETE. */
if (Lower($editContext.editType) != 'update') { return null }; 

/* Checking if the current field already has a value. If so, return that value. */
if (!IsEmpty($feature.last_inspection_date)) { return $feature.last_inspection_date};

... The rest of your code goes here and only executes if the above conditions are not met.

 

 

var GID = $feature.GlobalID;
var sortedRecords = OrderBy(Filter(FeatureSetByName($datastore, "Inlet_Inspections"), 'GUID = @GID'), "Date");

... The rest of your code here.​

 

- Justin Reynolds, PE