Filter choice with values from the same repeat

Hello.

I have a repeat group with a selec_one field. I'm trying to, according to the passt selected choices, filter the list for the next choices.
Ex. I have the following list:
1
2
3

In the first repeat I can chose any of them, but if I chose item '2', in the second iteration the list is presented as follows:
1
3
If now I chose item 1 the next iteration will just show the item '1':
1

Is there any way to do this using odk?

Welcome to the ODK forum, @ricardopmarinho ! We're glad you're here. When you get a chance, please introduce yourself on this forum thread.Thank you for adding a picture as your avatar; it helps build community!

Yes, what you ask is possible! Check out this thread (I think it answers your question):

Thanks for your reply, @danbjoseph.

Unfortunately the solution you showed don't solve my problem. In my case, I have to remove a possible choice from a list inside a repeat based on the previous choices at the same list.

To be clearer, I have a repeat group and a chose_one inside this group, for example, I have to chose between the numbers 1, 2, or 3.
If in the first iteraction I chose the number 2, when I go forward to the second iteraction, the same chose_one shouldn't have the number 2, just 1 and 3.

The thing is: I need to keep track of the previous choices in the same select_one to not show the ones I selected before.

Ah, apologies! I did not read your question closely enough. I can try and dig into this more later. Have you seen the documentation section on Repeat Recipes and Tips?

No problem. I've already seen this documentation part and couldn't find something to solve my issue.

Are you sure? It would be a little complicated but if you use choice filters functionality based on calculations including the indexed-repeat and position() function you could include, inside the repeat group, a calculation which calculates the previous answer. This answer could then be used to filter the choice list in the next round of the repeat. This is assuming that you know the maximum number of times the repeat count could run. If there is no limit to the repeat group, in theory it would still be possible but it would become more complicated again.

I've tried this but, for some reason, when I try to retrieve the value from past iterations at the same field, I can't make the form available for use.

This repeat have 15 iterations and 15 choices and I must know the value of each iteration to filter-choice.

My code was something like this:

begin_repeat | rep_group
select_one opt | opt_field | not(selected(indexed-repeat(${opt_field},${rep_group},position(..)-1)))

No it's not possible.

Can you confirm that its definitely not a "ranking" that you are creating as there seems to be some discussion on that topic recently?

I am not sure if the code you shared is a constraint or a choice filter but I dont think that would work as either: not(selected(indexed-repeat(${opt_field},${rep_group},position(..)-1)))

The selected function has two parameters. The first is a field name (not a calculation) and the second is a value from the choice lists. In your example there is only one parameter and its a calculation so I would guess it would not be possible to deploy like this.

The best may be to upload an xlsform or section of one and see if that makes things a little more clear.

sorry, it was soposed to be like this.

not(selected${opt_field}(indexed-repeat(${opt_field},${rep_group},position(..)-1)))

any way, if I try just the idexed-repeat like this (trying to get the previous value from the same field) it does not work

Is your form something you can share? Someone might have ideas about alternate ways to achieve the same thing.

sure.

form.xlsx (10.7 KB)

In this example I'm not trying to filter like I said, but already tryied to use the comand and didn't work

A post was split to a new topic: Filter options to remove previously selected choices

I came across this post while trying to do something very similar, and was able to identify a solution.

In a repeat loop, the choice_filter column can be used to filter out options selected in prior iterations of the repeat loop. This requires two pieces:

  1. A calculate filed added the line after end_repeat that joins the id's of the selected items.
  2. Using choice_filter to exclude items already selected.

For example,

type name label calculation choice_filter
begin_repeat items This is a loop
select_one item_select item_id Select Item not(selected(${id_join}, name))
end_repeat
calculate id_join join(' ', ${item_id})

Hope that helps.

2 Likes

@bpoulos or anyone who has implemented similar, does this calculation not work in Enketo? And can it be nested?

I have a nested repeat (Let's say the tree is country\state\city) and want the enumerator to first select a country, then be given a repeat(outer) to select the state, with repeat count = number of states in country, then for each state, be given another repeat(inner) to answer questions about the cities in that state (with repeat count = number of cities in state).

They should not be able to select any state or city twice.

Using the joined string calculate outside the repeat, when tested in Enketo, after selecting an option it is deselected automatically, so the state can never be selected to get to the city questions.

In Collect, for the outer repeat the option selects correctly, and the next repeat does remove the previously selected option(s). Then for the inner repeat (which has a calculate outside the inner repeat and inside the outer repeat), the next repeat does not remove the previously selected options.

Edit:
Rather than calculate the join outside the repeat, I have used a not(selected(join())) in the relevance field and this works in both Enketo and Collect.

Edit2:
works unless there are common values in the nested repeat (eg state Missouri and state Illinois both have city Springfield, so completing Missouri|Springfield removes Springfield as a choice when you are doing Illinois.

I assume there's a way to filter a join to the nodeset of values in the repeat in the repeat, and not all values for the nodeset in the repeat across all repeats. I'm getting somewhat lost in repeat syntax!

Someone pointed me to this thread from another channel. The solution presented above uses a join that includes all values selected, including the one selected in the question whose choices are being filtered. I believe that upon submission all values selected will always be cleared. It will appear to work during form entry because the filter is applied when determining choices to display and then not recomputed during further form entry. However, at form finalization time, everything will be recomputed and all values will be discarded.

I believe you'll need to do a join inside the repeat that excludes the current repeat instance's selection.

@ahblake were you able to get things to work as you wanted? If so, would you be up for sharing an example of what you did? If not and it's still something that would be helpful, I can take a look at how to approach it.

I forget exactly what i was working on here, but yes after a horrible couple late nights last year i created a beautiful working repeat in a repeat with dynamic counts for both that allows completion in any order and removes completed items from selection.

I'll try to pare it down to a example and post soon

3 Likes

Great to hear, @ahblake! No strong reason to post now since it doesn’t look like anyone has that exact need currently!

1 Like