Problem
invalidItems in the questionnaire response store is keyed by qItem.linkId. In a repeating group, every instance of a child item shares the same linkId. If one instance is invalid, invalidItems[linkId] is set and every rendered instance of that item shows the error — including instances with valid answers.
Example: a repeating group with a required text field. If the third instance is left empty and "Save as Final" is attempted, all instances show "This field is required", not just the empty one.
Affected validation types:
- Required — if one instance has no answer, all instances show the required error
- Format/range (regex, min/max, etc.) — if one instance has an invalid answer, all instances show the format error
targetConstraint — not covered by the fix below; see note
Effect on save gate
The save gate introduced in #1974 is unaffected — responseHasErrors correctly reflects whether any instance has errors. This is a display-only bug: errors appear on instances that don't deserve them after highlightRequiredItems() is called.
Proposed fix
Set a unique id on each child QuestionnaireResponseItem within repeat group instances — in useInitialiseRepeatGroups for existing QR data, and wherever new repeat instances are created.
Validation would then key invalidItems by qrItem.id ?? qItem.linkId, and useValidationFeedback (which receives qrItem) would look up the same key. Items outside repeating groups have no id set and fall back to linkId — no behaviour change for non-repeating items.
Files in scope: validate.ts, useValidationFeedback, repeat group initialisation hooks.
Note on targetConstraint in repeating groups
targetConstraint expressions are evaluated once against the entire QuestionnaireResponse as a document, returning a single true/false for the whole QR. There is no per-instance result — the constraint has no way to indicate which specific repeat instance violated it. Re-keying invalidItems by qrItem.id doesn't help here because the single isInvalid flag would still be stored under one key with no instance granularity.
Fixing this would require scoping the expression evaluation to each repeat instance separately — evaluating the constraint once per instance against that instance's subtree of the QR. This warrants a follow-up issue.
Problem
invalidItemsin the questionnaire response store is keyed byqItem.linkId. In a repeating group, every instance of a child item shares the samelinkId. If one instance is invalid,invalidItems[linkId]is set and every rendered instance of that item shows the error — including instances with valid answers.Example: a repeating group with a required text field. If the third instance is left empty and "Save as Final" is attempted, all instances show "This field is required", not just the empty one.
Affected validation types:
targetConstraint— not covered by the fix below; see noteEffect on save gate
The save gate introduced in #1974 is unaffected —
responseHasErrorscorrectly reflects whether any instance has errors. This is a display-only bug: errors appear on instances that don't deserve them afterhighlightRequiredItems()is called.Proposed fix
Set a unique
idon each childQuestionnaireResponseItemwithin repeat group instances — inuseInitialiseRepeatGroupsfor existing QR data, and wherever new repeat instances are created.Validation would then key
invalidItemsbyqrItem.id ?? qItem.linkId, anduseValidationFeedback(which receivesqrItem) would look up the same key. Items outside repeating groups have noidset and fall back tolinkId— no behaviour change for non-repeating items.Files in scope:
validate.ts,useValidationFeedback, repeat group initialisation hooks.Note on
targetConstraintin repeating groupstargetConstraintexpressions are evaluated once against the entireQuestionnaireResponseas a document, returning a singletrue/falsefor the whole QR. There is no per-instance result — the constraint has no way to indicate which specific repeat instance violated it. Re-keyinginvalidItemsbyqrItem.iddoesn't help here because the singleisInvalidflag would still be stored under one key with no instance granularity.Fixing this would require scoping the expression evaluation to each repeat instance separately — evaluating the constraint once per instance against that instance's subtree of the QR. This warrants a follow-up issue.