medic/cht-conf

`convert-contact-form` can break contact form with nested groups in `init` group

Opened this issue · 0 comments

Describe the bug

The convert-contact-forms action contains logic that manually manipulates the order of elements in the body section of the form xml. Basically, when the form contains a /data/contact group it will try to update the body section so that the /data/contact group is nested inside of the /data/init group.

So, an xml with a body like:

  <h:body class="pages">
    <group ref="/data/contact">
      ...
    </group>
    <group appearance="field-list" ref="/data/init">
       ...
    </group>
  </h:body>

becomes:

  <h:body class="pages">
    <group appearance="field-list" ref="/data/init">
       ...
      <group ref="/data/contact">
        ...
      </group>
    </group>
  </h:body>

Unfortunately the this logic seems to be bugged when /data/init contains a nested group. In that case, the form xml actually ends up being converted into:

  <h:body class="pages">
    <group appearance="field-list" ref="/data/init">
      ...
      <group ref="/data/init/non_relevant_group">
        ...
        <group ref="/data/contact">
          ...
        </group>
      </group>
    </group>
  </h:body>

Notice that /data/contact is now actually instead /data/init/non_relevant_group.

This does not seem to have any negative effects except when /data/init/non_relevant_group is non-relevant and /data/contact has calculate fields that should be evaluated. When that happens the /data/contact calculations will not be evaluated since they are regarded by Enketo as non-relevant.

To Reproduce

Create a contact-create form with the following contents (does not have to result in a "valid" contact:

type name label::en relevant appearance calculation
begin group contact NO_LABEL      
string parent NO_LABEL      
calculate first_name       ${first_name_contact}
end group contact        
begin group init NO_LABEL   field-list  
text first_name_contact Name      
begin group non_relevant_group NO_LABEL false()    
text non_relevant_question Should not see this      
end group non_relevant_group        
end group init        

Convert/upload the form with cht-conf, then open the form in the CHT. Enter a value into the "Name" field.

Then, in the browser console, run window.CHTCore.debugFormModel() to dump the current form model data.

The expected behavior is that data/contact/first_name should be populated with the same value you entered in data/init/fist_name_contact. However, this will not be the case in the dumped model data. Instead, data/contact/first_name is not populated at all (presumably because Enketo considers it to be non-relevant).

Expected behavior

I believe that if the convert-contact-forms action simply nested /data/contact inside /data/init (as a sibling of /data/init/non_relevant_group) everything would work as expected.

This convert-contact-form functionality was originally added in #25. I am not 100% sure, but this seems to have been a hack try to and work around medic/cht-core#8226. A better long-term solution might be to solve #8226 and then unjankify some of this contact form logic. At the very least we need more complete documentation regarding the required structure of contact forms....

Additional context

Originally reported on the forum.

One final note is that it this does not seem to be related to any specific Enketo version. I have reproduced the behavior on 3.17.2 and on master.