Enketo form load error with instance lookup in choice filter 'Cannot read properties of undefined (reading 'length')

1. What is the issue? Please be detailed.
A form that validates at upload and works in Collect cannot be loaded in Enketo with unclear error message.

Closest forum post for error text:

I put a choice filter inside a repeat that I was using to filter down a choice list with images to a single item so that it would show a select with a thumbnail, that can be enlarged as a reference view during data collection. This worked in Collect with no issues. (I know the images won't show in Enketo currently as a select one/multiple with a choice filter and big-image doesn't work - open issue - this also had some problems with a choice filter that used an instance lookup)

The choice filter was of the type;
name=instance('trees')/root/item[name=${selected_tree}]/tree_height

2. What steps can we take to reproduce this issue?
Put an instance lookup in a choice filter, load form in Enketo

3. What have you tried to fix the issue?
First calculate the value I need;
instance('trees')/root/item[name=${selected_tree}]/tree_height

Then reference that calculated field in the choice filter;
name=${separately_calculated_tree_height}

This loads in Enketo, choice filter functions correctly. (images don't show as expected). Still functions in Collect.

4. Upload any forms or screenshots you can share publicly below.
n/a

Did you check the form - and try to preview - with the Online validator?

It seems there is a closing ] bracket missing.

  1. ... instance('trees')/root/item[name=${selected_tree}/tree_height

Could you share a related extract of your XLSForm, please, including the choice example?

Per this earlier reply to you, that's redundant as it validated successfully when uploading to Central.

1 Like

Hi @ahblake
Sorry, we mostly use ODK Collect with KoboToolbox, as other users too. Thanks, for the Central check reminder.

2 Likes

The error is a Javascript exception so yes, it's very unhelpful.

Is this form roughly what you did? This seems to work so there's probably another condition needed. Maybe external file?

Fascinating! You shouldn't need to do that but it's good that works at least.

Yep! I took your example and built it back up to find the error - it's the presence of image that's doing it.

choice filter with instance lookup + image.xlsx (659.8 KB)

If you add an image column to the choice list for benches, the form will no longer load in Enketo, regardless of whether the images have been uploaded or not.

So you can have a choice filter that has an instance lookup OR images against the choices, but not both. If you need both, you must do the instance lookup separately and use that field in the choice filter.

This is related to my other issue with Enketo and choice filtering with images & big-images, but at that time form loaded but labels were blank (it was a combined or choice filter in that example though)

I've added this to the issue at https://github.com/enketo/enketo-express/issues/534

Looks like this is another rich bug vein. I'm glad you have a work around for now. We're still trying to figure out how to best approach a fix because these problems run deep.

I'll keep mining :wink:
Not being able to see the images in Enketo even with the workaround is annoying, but not a deal breaker currently.

Seems most of my issues are around doing things with images!

Tangent for others, creating a filtered select that has image & big-image is a handy way to serve up one to many reference media (without having lots of note fields with images and using relevance to show) that can also be zoom-panned. (It is just a shame that the default render on Samsung is so poor compared to the actual image quality)

1 Like

:pick: :beetle:

@LN I hit this one again, but no instance lookup in the choice filter and this time reading 'toString'. Form again validated, but threw an error when loading in Enketo. Form did load, but was broken with the affected fields and fields unrelated to it having issues.

Error occured during the loading of this form. We do not recommend you use this form for data entry until this is resolved.

Please contact support@getodk.org with the link to this page and the error message below:

FormLogicError: Could not evaluate: /model/instance[@id="ref_list"]/root/item[if( /model/instance[1]/data/grp_start/filter_preexisting !='',level= /model/instance[1]/data/grp_start/level and contains( /model/instance[1]/data/grp_start/filter_preexisting ,category), level= /model/instance[1]/data/grp_start/level ) and if( /model/instance[1]/data/grp_start/record_type ='report',category!='A',category='A')], message: Cannot read properties of undefined (reading 'toString')

previously working:

if(${filter_preexisting}!='',level=${level} and contains(${filter_preexisting},category), level=${level})`

caused error:

if(${filter_preexisting}!='',level=${level} and contains(${filter_preexisting},category) and if(${record_type}='report',category!='A',category='A') , level=${level}) and if(${record_type}='report',category!='A',category='A')

I've since reworked the logic to this and it doesn't throw any errors and appears to function correctly with no load errors in Enketo.

if(${record_type}='report',level=${level} and category='A',if(${filter_preexisting}!='',level=${level} and contains(${filter_preexisting},category), level=${level} and category!='A'))

And to rub salt into the wound I hit the dynamic read-only Enketo bug after!

Are you sure that you've tried every branch? I'm really surprised those two would have different results.

Do you have reason to think this is related to images as well?

Background;

  • Entity list has ~6000 items, each with a photo filename in the image field
  • Photos can't currently be shown under select labels from CSVs or Entity lists so the UUID/label/image/big-image are duplicated (by using the Entity OData URL to powerquery in these fields and spill into the choice list) from the Entity list as an internal choice list, to
    • force upload of media in Central
    • give a filtered select that shows images (Only in Collect, Enketo hates this one weird trick)
  • As the survey progresses I update an entity field (eg 'unsurveyed' to 'surveyed') and I don't want these items to appear after an upload and a sync, so I want to filter them out. I also don't want to have to update the definition with each upload.

At first, as Enketo doesn't like [*] a choice filter like this:
name=instance('entitylist')/root/item[${update_status}!='surveyed']/name

I tried the following, but it threw the same ‘Cannot read properties of undefined (reading ‘length’) error:
contains(join(' ',instance('entitylist')/root/item[${update_status}!='surveyed']/name),name)
So after screaming into the void for a while I searched the error and came back to this thread and figured, why not try calculating the join separately and then using it in the filter, and it worked! I think I spoke too soon:
calculate_field as join(' ',instance('entitylist')/root/item[${update_status}!='surveyed']/name)
choice filter as contains(${calculate_field},name)

Edit:

My join was breaking in Enketo, some didn't work, looks purely like the order of my expression=field vs field=expression in the instance prevented the join from working;

  • Not OK
    • join(' ',instance('entitylist')/root/item[substring-after(${update_subarea},'prefix_')=subarea and ${update_area}=area and survey_status!='Surveyed']/name)
  • OK
    • join(' ',instance('entitylist')/root/item[substring-after(${update_frame},'frame_')=frame and ${update_area}=area and survey_status!='Surveyed']/name)
    • join(' ',instance('entitylist')/root/item[substring-after(survey_status!='Surveyed']/name)
    • join(' ',instance('entitylist')/root/item[subarea=substring-after(${update_subarea},'prefix_') and ${update_area}=area and survey_status!='Surveyed']/name) :rage: :confetti_ball:

Based on that I tried skipping the separate join calc and recombining the working join with the contains as below, but of course Cannot read properties of undefined (reading 'length'):
contains(join(' ',instance('entitylist')/root/item[subarea=substring-after(${update_subarea},'prefix_') and ${update_area}=area and survey_status!='Surveyed']/name),name)

Edit 2:

I updated an entity from 'unsurveyed' to 'surveyed', it disappeared in Collect but not in Enketo. I swapped the survey_status around and got a whole new error in Enketo

Not sure how to handle: '{"stack":[{"t":"root","tokens":[{"t":"bool","v":false},{"t":"op","v":4},57005,{"t":"op","v":8}]}],"cur":{"v":"areaand"}}

So why not swap one more filter...
join(' ',instance('entitylist')/root/item[subarea=substring-after(${update_subarea},'prefix_') and area=${update_area} and 'Surveyed'!=survey_status]/name)

It works. In Collect and Enketo, correctly showing or hiding items with 'surveyed' status. That's all I can handle for today. :sleeping:


@Tyler_Depke re this thread, this might interest you, it validates the process of create an entity with a filename against it, query in the entity list and filenames to the form and use that as an internal choice list with images.

[*] I have lost most of today butting up against things Enketo doesn't like, including hours spent trying to understand what is unacceptable in a constraint expression but totally fine in a normal calculation/relevance, like using jr:choice-name, getting a true/false result from a count... :rage: