Dynamic update to selected items within a multi-select based on previous responses (not choice_filter)

I am trying to get a multi-select question to be populated by previous responses from within a repeat (the multi-select is outside, after the repeat). I want to be able to update the multi-select without going back through the repeats (because this is a summary and the repeat is long and tedious :slight_smile: ) - kind of a quick way adding what exists but has not been examined in detail, so that we can maybe go back later if more detail is really needed.

Importantly this is not about filtering out choices shown on the multi-select - more like 'see what you've already collected, have you missed (or not bothered to record) anything minor?', rather than only show what hasn't already been covered earlier.

Example:
The repeat includes a select_one (e.g. ${repeat_item}) that uses the same list as the multi-select from the choices tab. I would like to use the multi-select to show which items have already been selected (and allow additional items not in the repeat to be selected).

  • Choices A B C D E F
  • fill in 3 Repeats (select_one) A C E
  • Multi-select calculation should show all options (A B C D E F) but have A C E already selected. And be able to select other items

Setting a calculation in the multi-select as join(' ',${repeat_item}) populates the list.

So far, so good.

BUT, if the surveyor makes any changes to the multi-select, they are lost when any calculations are done (e.g. form save) and it resets to the list of ${repeat_item}

So this seems to be mainly about when calculations are performed... I can sort of fix it by adding a trigger based on a third (unrelated) question, that is outside the repeat I can retain the changes to the multi-select, which NEARLY meets my needs! Using once() on the calculation doesn't solve it either, for fairly obvious reasons.

I have not found a way to be able to update the repeats (either change, add or delete) and allow that to MODIFY the multi-select without losing any differences that were in the multi-select. I tried adding another calculate outside the repeat to 'hold' the extra items thinking it could concatenate with the Join, but I can't work out how to stop it being overwritten before the multi-select is reset.

So my question is: can this be done? I've asked Kapa and it didn't get as far as this but did recommend asking the Forum! So here I am...

The surveyor can update the list manually by going back to the repeats, but this is error-prone.

I know it's a bit 'niche'! It's about trying to speed up the initial field data collection - it is encounter-based survey rather than a predetermined list of activities or features, so we don't know what we don't know until we find it, and it may not be important enough to collect every aspect of every item because life is short :face_with_peeking_eye:

Ciao @seewhy

Good one indeed .. I am a fan of this type of controlling or monitoring repeats with select_multiple.

Best guess of undesired reset is likely cause led by where the join(' ',${repeat_item}) is placed. There could be many options to go around this:

  • if surveyor already knows which options or items their will monitor in the repeat, then use select_multiple to control both repeat_count() and pre-refilling select_item inside repeat. With this, you could apply the filter on the second select_multiple outside repeat to show items that were not used in the repeat. Any changes (delete repeats would be seamlessly managed and updated).
  • If the above is not the case, try putting the logic in default not as a calculation, but a reference to the calculate that holds join(' ',${repeat_item}), this will allow retention of user inputs in addition to default pull, but risks errors if user unintentionally deselect one of default values.
  • I personally prefer the first option, guaranteed control during collect and data process (no surprises). You can also add notes to remind surveyor previous inputs (since they won’t show on the recap select_multiple). I posted something similar in the past, will get the link if not share a sample XLSForm

Best,

Jules R

Hi @jules_rugwiro
Thanks for your input to this...

Unfortunately, I can't control the repeat number (your option 1), because it is unknown at the outset. It is an 'encounter survey' - so we don't know what's out there before setting off.If we could do it on two passes then I think I could use this approach. I have used this for longitudinal / case management surveys because, as you say, you can control what is in the survey and how many items to expect. But I live by surprises in data collection :face_with_spiral_eyes:

I tried the default option - which is similar to the calculate trigger option I described. They have the same weakness, although I can re-trigger the calculation by updating that third question. But that's still not capturing / retaining my 'manual' selections in the multi-select.

I think I may well have abused your ideas for notes :innocent: - they work well. In a similar survey form to the one I'm adapting, I have drawn out some of the detail from the repeats, exactly for the purpose you suggest. It is actually better if you have multiple responses of the same option than just a multi-select.

In this case I'm trying something 'different' to give me some nuance for a follow up stage, as we don't have resources to run a detailed survey for the entire area, but also don't know how 'bad' things might be - the idea is to get a 'ballpark' range of responses and then decide which areas to focus. So surveyors have guidance on 'how bad' something needs to be to report it individually then check-box the rest. Not perfect science, but hopefully pragmatic for our purposes (which isn't actually rocket-science!). Some call it quick and dirty, but then perfect can be the enemy of finished...

Hello @seewhy,

Last option that comes to mind is to hold repeats selections in memory/calculate (as you’re doing with the join), have one filtered select_multiple for manual selection and lastly, one last read_only select_multiple where you populate aggregated selections from both join() and those manually selected.

Loads of mechanics I know .. might be worth a shot though.

Best,

Jules R

And that's where I got lost! I couldn't get the mechanics / workflow right to pluck the manually selected items in the multi-select whilst repopulating it.

But then, inspired by your 'mechanics' I thought if I could extract only the manually selected items, then re-inject them... Because of how the array is built up, it adds newly selected items to the end of the array, I hoped this might work for ${intermediate}:

substring-after(${multi-select},join(' ',${repeat_item})) [with the trigger ${multi-select}]

then changed the calculate for ${multi-select} to concat(join(' ',${repeat_item}),${intermediate}) [no trigger].

And the rabbit comes out of the hat!

I can add items to the multi-select manually, and also go back into the repeat and add more (although I shouldn't need to). I even seem to be able to change existing repeat_item and delete them. But if I manually delete one of the ${repeat_item} checked in ${multi-select} it falls over - and resets to the pre-selected ${repeat-item} array. I guess that's expected behaviour as it can't find the substring-after - if there was a function to compare the array and remove each substring (i.e. each item in ${repeat_item} it might not break?

To summarise what kind of works:

${repeat_item} is in a repeat group with a select_one choices
${multi-select} is a multi-select outside the repeat with the same choices.
${multi-select} has a calculation (no trigger) of concat(join(' ',${repeat_item}),${intermediate})
${intermediate} is a calculate field with calculation of substring-after(${multi-select},join(' ',${repeat_item})) trigger ${multi-select}

${multi-select} is populated by any ${repeat_item} and can be updated manually. However, unchecking an item from the ${repeat_item} list breaks things... you can't 'not have' something you've already said you've got!

Thanks for lending me your intellect @jules_rugwiro ! Much appreciated - although it's not me-proof, most fools will get away with it, maybe by adding a note of caution in the hint... Not ticking SOLUTION just yet, in case anyone else has a better way round...

Ciao @seewhy

We are almost there .. below would be my approach (for earlier description)

  • build the calculate outside repeat, so changes in repeat update with ease
  • Use the join() to build the arrays

This might do.

Cheers,

Jules R

Nice! And safe.

It's not how I envisaged it, but it certainly works without danger of messing.
S02 is only the things that haven't been surveyed in detail, which is a good way of drawing attention to them.

Two tiny things that stop it working
choice-filter needs to be not(selected(${C01},name))
and the calculation needs an extra ' ' in the concat to make it a be recognised as a list
concat(${C01},' ',${C02})

Combining some ideas here to smooth the workflow, I could use this idea to add ${C01} to the label to be the reminder of what was surveyed in detail and then checkable other items (but with the usual problem of not getting a newline between items in an array and because I'm using it in the array I can't use the </br> workaround for Collect). But it would make S03 redundant.

But I like! Thanks. This is a solution that works with options of how to display the repeats