-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Correct support for using select questions with search and the last-saved feature #6802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v2025.2.x
Are you sure you want to change the base?
Changes from 7 commits
59658c6
be112eb
5e0e80c
ab8ca73
662be56
8ca4cea
401ceeb
80c1a4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,8 @@ | |
|
|
||
| import org.javarosa.core.model.SelectChoice; | ||
| import org.javarosa.core.model.condition.EvaluationContext; | ||
| import org.javarosa.core.model.data.IAnswerData; | ||
| import org.javarosa.core.model.data.helper.Selection; | ||
| import org.javarosa.core.model.instance.FormInstance; | ||
| import org.javarosa.form.api.FormEntryCaption; | ||
| import org.javarosa.form.api.FormEntryPrompt; | ||
|
|
@@ -210,6 +212,7 @@ public static ArrayList<SelectChoice> populateExternalChoices(FormEntryPrompt fo | |
| } | ||
| } | ||
| } | ||
| updateQuestionAnswer(formEntryPrompt, returnedChoices); | ||
| return returnedChoices; | ||
| } catch (Exception e) { | ||
| String fileName = String.valueOf(xpathfuncexpr.args[0].eval(null, null)); | ||
|
|
@@ -228,6 +231,23 @@ public static ArrayList<SelectChoice> populateExternalChoices(FormEntryPrompt fo | |
| } | ||
| } | ||
|
|
||
| private static void updateQuestionAnswer(FormEntryPrompt formEntryPrompt, List<SelectChoice> returnedChoices) { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the In these cases, we initially only have the raw XML value, since that's what gets stored in the submission. At that stage, external choices are not loaded yet, so we can’t resolve the user-visible label. But once the choices are loaded (exactly when we call this method), we can update the formEntryPrompt. Similar to haow JR deals with choices that it is aware of: https://github.com/getodk/javarosa/blob/master/src/main/java/org/javarosa/core/model/ItemsetBinding.java#L144 Why did this seem to work in earlier versions of the app? Mostly because of how operations were ordered. As I noted in the issue, I was able to reproduce bugs caused by the same underlying problem even in older versions. It was just less noticeable because calling certain functions in a particular order could update the answer internally in a similar way to what this fix now handles explicitly.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm worried about the performance implications of the change here as we end up doing a
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that doesn't seem like it'd be common. The case in the issue (using the value in a
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, depending on the answer's position in the list, the lookup might be very fast (if it's near the beginning) or require scanning the entire list (if it's one of the last entries).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, the average is still just "linear" (
Right. I'm worried that this implementation introduces a performance drop that could make using
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @seadowg, how many choices would you expect in such a form? I've built one with 2k (not that big, maybe) and was looking for one of the last elements. The operation was very fast and it took only 0.001s. Here is the form:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It’s hard to predict. Generally the list should be filtered but it could be big. I generally agree we should try not changing the perf characteristics much. There’s a loop over all choices right before. Could we identify the selected choice and save its label in that pass rather than doing an additional one?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think first we should have a benchmark that exercises the code paths here so we can make sure we have a measure of if there is a significant change or not (and protect ourselves moving forward). Potentially using the 100k item data set with a new form (that uses
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, this is possible, and I've just added this change. In this case, if there is no additional loop, I'm not sure if we need any benchmark test as a part of this pr? |
||
| IAnswerData value = formEntryPrompt.getAnswerValue(); | ||
| if (value == null) { | ||
| return; | ||
| } | ||
|
|
||
| Selection selection = (Selection) value.getValue(); | ||
| if (selection.index != -1) { | ||
| return; | ||
| } | ||
|
|
||
| returnedChoices.stream() | ||
| .filter(choice -> selection.getValue().equals(choice.getValue())) | ||
| .findFirst() | ||
| .ifPresent(selection::attachChoice); | ||
| } | ||
|
|
||
| /** | ||
| * We could simple return new String(displayColumns + "," + valueColumn) but we want to handle | ||
| * the cases | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -161,7 +161,6 @@ public ODKView( | |
| LifecycleOwner viewLifecycle | ||
| ) { | ||
| super(context); | ||
| updateQuestions(questionPrompts); | ||
|
|
||
| this.viewLifecycle = viewLifecycle; | ||
| this.audioPlayer = audioPlayer; | ||
|
|
@@ -209,6 +208,7 @@ public ODKView( | |
|
|
||
| setupAudioErrors(); | ||
| autoplayIfNeeded(advancingPage); | ||
| updateQuestions(questionPrompts); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One of the steps performed by For select-type questions, the underlying data is represented by |
||
| } | ||
|
|
||
| private void setupAudioErrors() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| <?xml version="1.0"?> | ||
| <h:html | ||
| xmlns="http://www.w3.org/2002/xforms" | ||
| xmlns:h="http://www.w3.org/1999/xhtml" | ||
| xmlns:ev="http://www.w3.org/2001/xml-events" | ||
| xmlns:xsd="http://www.w3.org/2001/XMLSchema" | ||
| xmlns:jr="http://openrosa.org/javarosa" | ||
| xmlns:orx="http://openrosa.org/xforms" | ||
| xmlns:odk="http://www.opendatakit.org/xforms"> | ||
| <h:head> | ||
| <h:title>Search with last-saved</h:title> | ||
| <model odk:xforms-version="1.0.0"> | ||
| <instance> | ||
| <data id="search-with-last-saved"> | ||
| <fruit/> | ||
| <group> | ||
| <fruit2/> | ||
| <details/> | ||
| </group> | ||
| <meta> | ||
| <instanceID/> | ||
| </meta> | ||
| </data> | ||
| </instance> | ||
| <instance id="__last-saved" src="jr://instance/last-saved"/> | ||
| <bind nodeset="/data/fruit" type="string"/> | ||
| <setvalue ref="/data/fruit" value=" instance('__last-saved')/data/fruit " event="odk-instance-first-load"/> | ||
| <bind nodeset="/data/group/fruit2" type="string"/> | ||
| <setvalue ref="/data/group/fruit2" value=" instance('__last-saved')/data/group/fruit2 " event="odk-instance-first-load"/> | ||
| <bind nodeset="/data/group/details" type="string"/> | ||
| <bind nodeset="/data/meta/instanceID" type="string" readonly="true()" jr:preload="uid"/> | ||
| </model> | ||
| </h:head> | ||
| <h:body> | ||
| <select1 ref="/data/fruit" appearance="search('fruits')"> | ||
| <label>Select fruit 1</label> | ||
| <item> | ||
| <label>name</label> | ||
| <value>name_key</value> | ||
| </item> | ||
| </select1> | ||
| <group appearance="field-list" ref="/data/group"> | ||
| <select1 ref="/data/group/fruit2" appearance="search('fruits')"> | ||
| <label>Select fruit 2</label> | ||
| <item> | ||
| <label>name</label> | ||
| <value>name_key</value> | ||
| </item> | ||
| </select1> | ||
| <input ref="/data/group/details"> | ||
| <label>Fruit details</label> | ||
| </input> | ||
| </group> | ||
| </h:body> | ||
| </h:html> |

Uh oh!
There was an error while loading. Please reload this page.