PLACE_TYPE behaviour clarification

As the title suggests, we’re trying to better understand the behaviour of the PLACE_TYPE variable. We’re also wondering whether there’s a PERSON_TYPE counterpart that we may not be aware of.

After reviewing the generic form doc, we noticed some differences between the documented approach and our current setup.

In our project:

  • We have a generic PLACE_TYPE-create/edit form and a place-types.json file in the contact folder. These haven’t been modified since the initial repo setup.
  • We also maintain type- and level- specific contact forms, which we update regularly.

What’s interesting is that although we use type/level-specific create/edit forms (rather than these generic forms), we’re still able to access and use the PLACE_TYPE variable within those forms. And seemingly have for a long while. It resolves correctly, even for some newer place types that are NOT defined in the place-types.json file (maybe worth to note that it’s just the normal types with a “ff_” prefix (feature flagged)).

What’s nice is that it makes it easier to share pieces of functionality across forms with fewer edits than expected. Important to note, parts are reusable - not the full form.

Even more interestingly, person forms appear to exhibit somewhat similar behaviour. This one threw us a bit. While using PLACE_TYPE directly (e.g., as the group name of the data persistence block, as we do for places) does not seem to work for people, we are still able to reference values FROM the persistence block successfully.

Resolves:


Above fields in xlsx:
image
Persistence block:
image

We’re trying to determine:

  • Is this expected behaviour? Is PLACE_TYPE resolved more dynamically than the docs imply?
  • Or are we relying on behaviour that could break in future updates?

So… The logic for resolving PLACE_TYPE in the form config is appallingly primitive. :grimacing: :person_facepalming: :sweat_smile: That being said, it has “worked” for 9 years now, so… :person_shrugging:

Looking at that linked code does explain the behavior you are observing:

  • It is applied to every contact form. Not just place forms and not just forms generated from the PLACE_TYPE-create/edit.xlsx files.
  • It does a blind regex replace of 'PLACE_TYPE' with the type value extracted from the form’s file name. (And not from the place-types.json). I suppose this is why your custom types are working.

That being said, I would stop short of calling this “expected behavior”.

On one hand, it has been like this for 9 years, so maybe the chances of this changing anytime soon are pretty low. :thinking: On the other hand, from my perspective I would consider this PLACE_TYPE replacement logic to belong to the PLACE_TYPE-create/edit.xlsx workflow and I would not guarantee it will continue to work in any other context.

This is very interesting! When you say “reusable” do you just mean that you are copy/pasting blocks of rows between xlsx files? For years we have been trying to figure out ways to reduce the maintenance effort in these forms. I think this was the original goal of the PLACE_TYPE-create/edit.xlsx functionality. Unfortunately, the contact hierarchy structure/complexity looks very different now than it did 9 years ago and I am not sure that feature is providing much value anymore.

I wonder if it would be best to introduce a generic CONTACT_TYPE placeholder value that would function similar to how you are using PLACE_TYPE currently, but would not be tied to or dependent on the PLACE_TYPE-create/edit.xlsx workflow? (Maybe we could even deprecate/remove/replace that workflow…)

It seems like if this functionality is providing value, we should support it.

2 Likes

It is a feature :eyes: :sweat_smile:, one we’ve actually been able to benefit from quite a bit.

In our configuration we try to create two separate “spaces”. Nothing fancy, we basically duplicate each form and prepend them with ff_. With a few contact summary tweaks to help surface them where appropriate, these become our feature-flagged forms.

This allows us to push frequent config changes to our non-prod space without blocking our ability to ship production releases. A lesson learnt during our audit. Longer-running form improvements (such as those identified in an audit) can spend time being tested and hardened in this space before being moved into the normal/regular flow.

That said, as a small team, maintaining all these files can become quite taxing. Even without the feature-flagged space, it’s very easy to forget to update something small in the contact create or edit form when you’re making a lot of changes under pressure.

Since the workshop where Diana joined (I’m stilling planning on returning to the questions on that doc), we’ve been trying to carve out some time for long-overdue cleanup. One of the things we tackled was “condensing” our contact forms.

CHT supports using the same form for both create and edit, as documented here:

So instead of maintaining two forms per contact type, we now only maintain one. Or two when considering FF. Still better than 4 :eyes:.

When we’re happy with the changes made to the FF contact content, transferring those changes to the main flow is fairly straightforward:

  • replace the survey sheet content
  • replace the choices sheet content
  • update any select-contact type-<type> references that point to ff_ contacts

It is probably worth noting that our condensed contact forms load previously captured contact data into placeholder variables, which are then referenced by the question fields for pre-population where needed.

However, now that we can reference PLACE_TYPE, transferring content between forms has become much less tedious. And hopefully less error prone.

For example, most of our contact forms now follow a pattern like this:

type name calculation
begin group capture
calculate prev_name once(string(../../PLACE_TYPE/name))
string name once(${prev_name})
end group capture
begin group PLACE_TYPE
calculate name ../../capture/name
end group PLACE_TYPE

This approach has allowed us to effectively halve the number of contact forms we maintain. It also meant we could remove the PLACE_TYPE-create/edit template forms entirely since they’re not required to achieve the behaviour we want.

As explained, because the type value is extracted directly from the form filename, we didn’t need to add any entries to place-types.json. The file simply needs to exist for the replacement logic in cht-conf to work. A good thing because referencing a contact that doesn’t have an edit form will cause the tool to complain.

Personally, I’d prefer not to keep an empty file around whose purpose isn’t too obvious (and which can’t even contain comments), but for now it works.

So I’m inclined to agree with your suggestion of introducing something like a CONTACT_TYPE placeholder. That would make a lot more sense for person forms in particular.

TLDR: yes please support it :folded_hands:

Nice! Thanks for the additional details here @Anro. As I was going to log a GitHub issue for this, I did find this existing one that is related. Let me know if you think it might be useful to have multiple template options instead of just a single PLACE_TYPE. seems like if we want to support a CONTACT_TYPE placeholder, that might naturally fit in with transitioning our PLACE_TYPE-create/edit.xlsx functionality to something more generic/flexible…

While I don’t think a purely generic template would fully address our needs, I can see how it might be useful in some project configurations. Our primary interest is more about dynamically mutating content within a form (per “space”) using placeholder variables (e.g PLACE_TYPE).

That said, I may be underestimating the value of combining both approaches. If we can supply dynamic variables, maybe via the .properties file, alongside more flexible templates, it should be possible to support a wide range of hierarchy-level contacts. Even where there are differences in structure and complexity.

Consider a CHW form vs a household member form. The latter captures significantly more detail, but they both share common fields such as name, email, and phone_number.

If I understand it correctly, PLACE_TYPE is replaced indiscriminately. So, this value can be captured as a string value on a calculate field that is then used for skip logic:

type name relevant calculate
calculate type “PLACE_TYPE”
begin group personal_details ${type} = “hhm”

In combination with the issue OP’s feature request, this can further reduce an implementers form bloat.

On the point of dynamic placeholder vars, it is something that would be useful to us because it’ll reduce the need for manual find & replace when moving forms over from the FF space into the regular/normal flow. Both the contact & app forms have database lookups that refer to specific contact types. As I mentioned here:

Speaking under correction, I don’t think there’s a way to dynamically set that reference in the form alone, right? Being able to supply some dynamic placeholder vars would help:

INDIVIDUAL_LOOKUP_TYPE = 'hhm' / 'ff_hhm'
HOUSEHOLD_LOOKUP_TYPE = 'household' / 'ff_household'
DWELLING_LOOKUP_TYPE = 'dwelling' / 'ff_dwelling'

To bring it back home, it would also help in cases where the primary contact needs to be selected for that place level. E.g:

Facility -> Nurse
CHW Area -> CHW
Household -> Household member

The referenced issue link:
Ability to use additional generic contact form templates · Issue #474 · medic/cht-conf