Once() function from ODK in CommCare?

Hi there,

It seems in ODK, there's a function called once() that can prevent multiple evaluation by only being evaluated the first time a field is populated:

https://docs.getodk.org/form-logic/

This allows for me to time when users reach particular points in a form by combining once() and now().

However, it seems once() has not been implemented in CommCare yet, as I get the error message 'cannot handle function once()'?

It would be great if this function could be implemented, as it is very useful for our work to be able to time interviewers reaching specific branching points.

Thanks for any help you may offer!

The CommCare XForms engine supports native trigger events for default values rather than the odk specific "once" concept. In the form builder, you can use that by defining xpath expressions in the Default Value field for a question or Hidden Value.

Unfortunately there's not a particularly consistent way to build the interaction you are describing, since CommCare XForms are supported across a variety of platforms and modalities, some of which display the entire form at once. As a result, the concept of "reaching" a specific point in the form can get kind of fuzzy.

I think you might be able to create the timestamping you are describing, though, as long as your form will be used on mobile devices. On Android, the now() function by default only ever triggers once, so if you create a hidden value calculation like

if(#form/question_to_timestamp = '', '', format-date(now(), '%H:%M:%S'))

The time will be locked in when the question question_to_timestamp was answered for the first time, and I believe won't be recalculated later. I tested this quickly with the questions below (you can copy the text and paste it into the Form Builder to create the questions) and it seemed to do what I expected.

-Clayton

Form Builder clip version 1
id type labelItext:en-default labelItext:est-default labelItext:hin-default calculateAttr
/question_one Select First question answered null
/question_one/yes Choice yes yes yes null
/question8 DataBindOnly null null null if(#form/question_one = '', '', format-date(now(), '%H:%M:%S'))
/question_two Select Second question answered null
/question_two/yes Choice yes yes yes null
/question9 DataBindOnly null null null if(#form/question_two = '', '', format-date(now(), '%H:%M:%S'))

Sorry for the late response, but only got an opportunity to test it out now - it seems to work really well. Thanks for the help!

Actually, I just tested it further and it doesn't work - if the user moves back to the original question after having visited it earlier, the time signature updates with the new time. Is there any way to prevent this from happening?