Survey123 Tricks of the Trade: Calculation modes

14610
16
09-22-2022 05:58 PM
IsmaelChivite
Esri Notable Contributor
8 16 14.6K

 

In a Survey123 form, you can automatically set the value of a question using an XLSForm expression in the calculation column. In the following example, the asset condition value is automatically calculated based on a checklist. If the three elements in the checklist are ticked, the condition is set to Good, otherwise the value is set to Needs repair.

Untitled Project.gif

 

Calculations are used for different purposes. Sometimes, we want to save the end user from answering questions for which we already know the answer. For example, the age of a person can be automatically calculated if we already know the birth date.  If we are given the length of a pipe and the price per meter, we can also calculate the total price of the pipe.  

In other occasions, we use calculations to provide a best guess, which the user can override.

This blog post introduces the concept of calculation modes. They will allow you to better control when  calculations are evaluated.

Calculation mode: auto

 

Unless specified otherwise, calculations are always executed in auto mode. When in auto mode, calculation expressions are evaluated when any of the inputs in the calculation expression change. For example, say you write a calculation to convert a temperature value from Fahrenheit to Celsius. Whenever the Fahrenheit value changes, the Celsius temperature is calculated.

TempChangeB.gif

 

Calculations in auto mode will not overwrite a value entered by the end user. For example, if the end user manually enters a value in the calculated question, the temperature conversion will be suspended. Note in the animation below how the Celsius temperature stops being automatically calculated as soon as its value is manually set to 34.

TempChange2B.gif

 

While the calculation is suspended, Survey123 will display a Calculate icon on the side to allow the end user to manually trigger the calculation. Only if the end user taps on that button to run the calculation, the expression will be evaluated again.

TempChange3B.gif

 

Calculations in auto mode are also suspended when an existing record is loaded into a survey. That is, when you open a survey from the Inbox, or when you load a record into the web app to edit it. This is because, again, in auto mode we do not want to overwrite a value that may have been manually added by the user.

In the vast majority of cases, you will find the auto calculation mode fit well your workflow. You do not need to do anything special to set your calculation in auto mode: Add an expression into the calculation mode, and you are set!  

If you want to set the calculation mode explicitly, go into the bind::esri:parameters column, and add calculationMode=auto, as shown in the next screenshot.

IsmaelChivite_0-1663892804476.png

The auto calculation mode is supported in both the field and web apps.

Calculation mode: manual

 

This one is easy. The question will only calculate when the Calculate button next to the question is pressed.

TempChange4B.gif

This calculation mode is only supported in the field app. The Survey123 web app does not support it.

Calculation mode: always

 

Set the calculationMode to always, and your calculation will never be suspended. It will run always, no exceptions. If the user manually resets the calculated value, as soon as any referenced variable in the calculation changes, the expression will be evaluated.The calculation will also be triggered when the form is submitted, just in case!

TempChange4.gif

I find calculationMode=always particularly useful when working with the Inbox. Lets take the example in the screenshot below: Row 6 is using calculationMode=always because we want its value to be always calculated, even if the record is opened in edit mode. 

IsmaelChivite_2-1663890873511.png

In the example above, if you keep the calculationMode as auto, the inspected_by value would remain unchanged if you open the record from the Inbox.

Here you have another variation of the survey:

IsmaelChivite_3-1663891052172.png

In this case, the survey uses a repeat, so you can have information about the asset, and a history of all inspections performed. We use calculationMode=always to keep the last inspection date and last known condition up to date.  Both of these values use data from the inspections table. Again, calculationMode=always helps us make sure these values are refreshed even if he record is loaded from the Inbox.

This calculation mode is only supported in the field app. The Survey123 web app does not support it.

Calculation mode: whenEmpty

 

As you may expect, calculationMode=whenEmpty will only trigger the calculation when the target question is empty.  If you are creating a new record or editing it, makes no difference: this calculation mode will be triggered if the question is empty.  Once a nonempty value is returned, the question behaves in the same way as the manual mode.

Check row 7 in the screenshot below. In this case we use calculationMode=whenEmpty to populate the inspection date with the current time, but only if the value is empty. That is, if you are opening an inspection record from the past, the value will not be overwritten, but if you are creating a new inspection record, the value will be automatically populated.

IsmaelChivite_1-1663893463281.png

This calculation mode is only supported in the field app. The Survey123 web app does not support it.

Force calculations in the Survey123 web app

 

The Survey123 web application, at the time when I write this, only supports the auto calculation mode. However, if you happen to be using the Survey123 web app to edit a record, and you want certain calculations to be triggered when the record is loaded, you can.

The recalculate url parameter allows you to specify which questions should be recalculated when the form is opened in edit mode.  If you are not familiar with web app url parameters, check this blog.

For example: ?recalculate=field:inspector,field:inspection_date will trigger calculations, and overwrite existing values, for the inspector and inspection_date questions.

You can also use ?recalculate=true to trigger all calculations in the form when the form loads in edit mode.

16 Comments
Hussam_AlJabri
Occasional Contributor III

Great improvement in the calculation @IsmaelChivite, Thanks.

survey123_solutions
New Contributor III

Excellent article, as always Ismael!  Thank you.

DeonLengton
Esri Contributor

Neither forceRecalculate nor recalculate seem to work for me -  here is my url syntax:

https://survey123.arcgis.com/share/xxx?portalUrl=https://www.sagns.gov.za/portal&mode=edit&globalId=%7Bglobalid%7D&width=800&hide=header,footer,navbar&forceRecalculate=user_is_pgnc,user_level 

https://survey123.arcgis.com/share/xxx?portalUrl=https://www.sagns.gov.za/portal&mode=edit&globalId=...

I've tried moving the parameters around, but still couldn't get it working.

Am I missing something?

SuddhaGraves1
New Contributor II

I have a field {SampleDate_Text} with the appearance set to hidden which converts a date/time field ${SampleDate} to a text field.  When I submit a record the calculation works as intended.  However, if I access it via the Inbox and edit the source date/time field, the hidden {SampleDate_Text} field does not perform the calculation as desired.  Is anyone else seeing this or similar issue?

IsmaelChivite
Esri Notable Contributor

@DeonLengton  You are missing field: in your URL syntax.

Change from this:

&recalculate=user_is_pgnc,user_level

 

To this:

&recalculate=field:user_is_pgnc,field:user_level

 

https://survey123.arcgis.com/share/xxx?portalUrl=https://www.sagns.gov.za/portal&mode=edit&globalId=%7Bglobalid%7D&width=800&hide=header,footer,navbar&recalculate=field:user_is_pgnc,field:user_level

 

AdriannaBarton
New Contributor III

I have calculationMode=always within a repeat table. When the calculated value (outside of the repeat) is adjusted the calculate does not rerun for all of the repeat records, only for whichever is 'open'. It would be nice if this were noted in the calculationMode esri notes for transparency.

Daniel_Perkins
New Contributor III

@AdriannaBarton great thought. I ran into the same issue. Would also be nice if there was a way to force each field in the related record to be updated in a similar way.

For example, in my workflow, we capture some metadata in the "core" portion of the form, and within the repeats we reference the core data to ensure folks only have to capture that data once. When the core data is changed later thru inbox, (e.g. changing the data from "not reviewed" to "reviewed")... the related records do not all update...

LJackson29
Occasional Contributor III

@IsmaelChivite I have a survey123 connect form built from an existing feature service. The survey is pulled into an experience builder app both in add and edit modes. Is there a way I can have all fields recalculate automatically when I am in edit mode? Some of my calculation fields are hidden, and others are based upon data in repeats and I doubtful users will remember to go to main section hit recalculate after updating data in a repeat. Edit mode in the experience builder app is triggered by selecting a feature in a list.

BE4
by
New Contributor II

Very disappointing to not have more web functionality. Currently running into hurdles with editing surveys recalculating fields that should be static.

RobertAnderson3
MVP Regular Contributor

I'm sure it's a bit of a dream but I really would appreciate a kind of "only run the calculation if this other question is a certain value"

For example, I have a form collecting asset information for a work order, some activities (selected outside of repeat) will have a GENERIC ID, so I have it set to calculate the ASSET TYPE to "GENERIC" or 'Standard Type' if not, allowing them to pick a specific UNITID.

The issue is, because it's in a repeat and I have calcMode=always set, when they cycle back through the repeat if they had selected 'Different Type' it will reset the type back to 'Standard'.

What I've done is just take out this calculation for now to avoid issues, but I like having defaults/calculations set to make it faster for my users.

If anyone has a solution (or if what I said doesn't make sense) let me know!

MichaelBruening
Occasional Contributor

@RobertAnderson3it sounds like you need to set your calculation to "auto" in order for the question's initial answer to be captured; according to the explanation above, but then to allow fo rit to be updated if needed.

In the past I have used the "once()" around my calculation within the "Calculation" column to acquire the data once. It also sounds as if you might need an if() within the calculation as well, since you only want it to be triggered when a certain value has been selected.

Here is an example of a complex once(if()) type statement that is depenedent upon a certain value being selected from within a repeat and then being applied to a field outside of the repeat.

once(if(${BC_Net_ID}=(concat(${KM_SiteID},'A')),(round(${NetA_LatDD_Final},7)),''))

JerrySneary
New Contributor III

Hi @IsmaelChivite , 

The parameter calculationMode=whenEmpty has stopped working for me. It's been working for almost a year. After a process of elimination, I found that if I turn off "readonly" it works, but if I turn off "readonly" it gives the submitter the ability to recalculate the field which I do not want to happen. Why is this happening, is this a new bug or expected behavior now after one of the updates?

***Update***

Come to find out it was a bug/glitch. CalculationMode=whenEmpty has been working for me in the web app for a year. Now it's no longer working or should I say it's working as it should. I have found that if I wrap my calculation with once() it serves the same purpose as CalculationMode=whenEmpty.

Kind regards,

Jerry

RobertAnderson3
MVP Regular Contributor

@MichaelBruening 

I have had it set up as auto, that is when it does work. I do have it set up as an if statement currently, the if needs that "else" option so I have that set to '' but if I re-open the survey to edit, or switch back to that entry on the repeat causes the input to be cleared, which I don't want.

if(selected(${AssetType},'GENERIC TREE'),'GENERIC TREE','')

So in this case, in a repeat, if the AssetType is generic, I just fill that into my ID field for summarizing/reporting. Otherwise I leave it blank so the user can enter the appropriate ID. However, when calcMode=always is on, when I return to it, it will blank out that input because of this expression.

The once() did not change this behaviour. I'd love a way to say "Do nothing" instead of '' for the else.

Teresa_Blader
Occasional Contributor III

I hope some day soon we can have calculationMode=whenEmpty available for Survey123 web app. I often use 2 forms to submit to an existing feature service, where the first form only contains certain fields for new feature, and then next form, used for editing/supplementing existing feature, contains additional fields that weren't in form 1 - usually like a QAQC field, or a status field, or some pull data fields - so there is no concern for overwriting a previously calculated field. Being able to auto-trigger those calculations on form 2 would be really helpful. Though at least recalculate button is available! - though I wish I could customize or make one recalculate button for a whole group of questions - instead of big bulky recalculate buttons over and over again. 

EricaNova
Occasional Contributor

I'm working with a form that has a "parent" layer and a "child" layer (the "child" is created using a repeat and uses rounded lats and longs from the "parent" layer).

The "child" layer has duplicates of many fields from the parent layer, using calculations like ${field1} where I set calculationMode=always.

Edits to the parent layer are recalculated in the child layer when I edit records one by one in S123 web app (yay!), but if I try to batch-edit records in ArcGIS Pro in the "parent" layer, the "child layer" data are not automatically updated.

Is there a way to force the data in the child layer (repeat) to always reflect what is in the parent?

lannguyentl
New Contributor III

Hi everyone,

Is there any way to calculate only while submitting (or let's say after hitting the submit button)? In my workflow, after user adds his signature and then submit the form, I would like to recalculate a field call survey_mode from "editable" to "readonly" so that this record will be readonly when user call it back through Inbox.

Currently, calculation trigger right after the signature is added. It is not convenient as user may want to replace his signature.

We can use a tasked python script to assist this update. However, it would be better with S123 only.

Thanks,

Lan