The panel-level validation is still incorrect. I tested the latest change and found a specific inconsistent case.
IMPORTANT: Before changing anything, inspect the CURRENT implementation and understand exactly why the panel-level validation behaves differently between panels.
==================================================
SCOPE — VERY IMPORTANT
==================================================
This is NOT specific to one Audit, one Audit workflow, or one Audit type.
We are building a GENERIC solution that must work across ALL audit types, all audit templates/configurations, and all generic Panel / PanelDynamic structures in the application.
The panels mentioned below are ONLY examples from my current test audit:
- Past Medical History and Review of Systems (ROS)
- Physical Examination and Diagnostic Assessments
- Medication Reconciliation and Plan of Care
DO NOT hardcode or create special logic for these panels.
The same implementation must automatically work for:
- Every Audit type
- Every audit configuration/template
- Every generic Panel
- Every PanelDynamic
- Nested panels
- Any number of required questions
- Any supported question type
- Any panel hierarchy
Do NOT create separate logic for different Audit types.
Do NOT add Audit-specific conditions.
Do NOT hardcode panel names, question names, question IDs, or Audit IDs.
The solution must be based only on the generic relationship between a Panel/PanelDynamic and its descendant questions.
==================================================
EXPECTED BEHAVIOR
==================================================
For EVERY generic Panel / PanelDynamic, the panel must show its own
"Response required." whenever AT LEAST ONE required descendant question
inside that panel remains unanswered.
Example:
Panel:
"Past Medical History and Review of Systems (ROS)"
Suppose it contains 5 required questions:
Q1 = answered
Q2 = answered
Q3 = unanswered
Q4 = unanswered
Q5 = unanswered
Expected UI:
Panel
"Past Medical History and Review of Systems (ROS)"
Response required.
<-- PANEL-LEVEL message MUST remain visible
Q1
(answered)
Q2
(answered)
Q3
Response required.
<-- QUESTION-LEVEL validation
Q4
Response required.
<-- QUESTION-LEVEL validation
Q5
Response required.
<-- QUESTION-LEVEL validation
The important rule is:
Panel-level validation means:
"Does this panel contain ANY unanswered required descendant question?"
It does NOT mean:
"Are all questions in the panel unanswered?"
==================================================
GENERIC VALIDATION LOGIC
==================================================
Conceptually the logic should be:
const hasUnansweredRequiredQuestion =
getAllDescendantQuestions(panel).some(question =>
question.isRequired &&
question.value is unanswered
);
if (hasUnansweredRequiredQuestion) {
showPanelResponseRequired();
} else {
hidePanelResponseRequired();
}
Therefore:
0 unanswered required questions
→ NO panel-level "Response required."
1 unanswered required question
→ SHOW panel-level "Response required."
2 unanswered required questions
→ SHOW panel-level "Response required."
10 unanswered required questions
→ SHOW panel-level "Response required."
The panel-level message must disappear ONLY when the LAST unanswered
required descendant question is answered.
==================================================
CURRENT BUG
==================================================
After answering some questions inside a panel, the panel-level
"Response required." disappears even though other required questions
inside the SAME panel are still unanswered.
For example:
Initial state:
Q1 = unanswered
Q2 = unanswered
Q3 = unanswered
Panel:
Response required.
Q1:
Response required.
Q2:
Response required.
Q3:
Response required.
After answering Q1:
Panel:
Response required.
<-- MUST STILL BE VISIBLE
Q2:
Response required.
Q3:
Response required.
After answering Q2:
Panel:
Response required.
<-- MUST STILL BE VISIBLE
Q3:
Response required.
After answering Q3:
Panel:
NO panel-level Response required.
This is the required behavior.
==================================================
IMPORTANT: DO NOT USE DOM VISIBILITY
==================================================
Do NOT determine the panel aggregate validation state using:
- Currently visible DOM elements
- Currently rendered questions
- Open/closed state
- Expanded/collapsed state
- Focus state
- Navigation state
- Scroll position
- Currently visible children
- Which question is currently focused
The aggregate state must come from the SurveyJS model/question hierarchy,
not from what happens to be visible in the DOM.
==================================================
NESTED PANELS
==================================================
Nested panels MUST also work generically.
Example:
Panel A
Panel B
Q1 = unanswered
Expected:
Panel B
Response required.
Panel A
Response required.
If Q1 is answered:
Panel B
No Response required.
Panel A
No Response required.
If Panel B contains another unanswered required question, both Panel B
and all relevant ancestor Panels must continue showing their own
"Response required."
This must work for arbitrary nesting depth.
==================================================
QUESTION-LEVEL VALIDATION
==================================================
Do NOT change the existing question-level validation behavior.
Individual questions must continue to show their own:
"Response required."
The panel-level validation is an ADDITIONAL aggregate state.
For example:
Panel
Response required.
Q1
Response required.
Q2
Response required.
Q3
Response required.
After answering Q1:
Panel
Response required.
<-- STILL PRESENT
Q2
Response required.
Q3
Response required.
The panel-level message must NOT disappear just because one child question
was answered.
==================================================
DEBUG THE ROOT CAUSE FIRST
==================================================
Before modifying the code, inspect the current implementation and explain
exactly why this inconsistency occurs.
Specifically investigate:
1. How panel-level validation is currently calculated.
2. Whether the implementation depends on panel.errors.
3. Whether answering one child question clears the parent panel's error
state.
4. Whether only currently invalid/rendered child elements are being checked.
5. Whether the current implementation checks ALL descendant questions.
6. Whether nested Panels / PanelDynamic are traversed correctly.
7. Whether SurveyJS validation state is being used incorrectly for
aggregate panel validation.
8. Whether panel validation is being derived from the first/last child
instead of the complete descendant question set.
9. Why "Past Medical History and Review of Systems (ROS)" loses the
panel-level error after some questions are answered while other panels
may still display it.
Do not assume the existing logic is correct.
Identify the actual root cause from the current code first.
==================================================
MINIMAL FIX ONLY
==================================================
After understanding the current implementation, make the MINIMAL GENERIC
fix required to correctly calculate the panel-level aggregate validation.
Prefer a reusable generic helper/function such as:
hasUnansweredRequiredDescendant(panel)
or an equivalent approach that fits the existing architecture.
The helper should:
- Work with Panel and PanelDynamic.
- Traverse all descendant questions.
- Include questions nested inside child Panels/PanelDynamic.
- Check required questions.
- Determine whether each required question is actually unanswered.
- Return TRUE if at least one required descendant is unanswered.
- Return FALSE only when all required descendants are answered.
- Not depend on DOM visibility.
- Not depend on open/closed state.
- Not depend on focus/navigation.
- Not depend on panel names.
- Not depend on question IDs.
- Not depend on Audit type.
- Not depend on the current audit configuration.
Reuse the existing validation/rendering mechanism where possible.
Do not rewrite unrelated validation code.
==================================================
DO NOT TOUCH THESE AREAS
==================================================
Do NOT modify:
- getExactQuestionElement()
- scroll/focus behavior
- navigation behavior
- findFirstInvalidQuestion()
- pendingTargetQuestion
- Audit/IP/Attestation validation separation
- existing question-level validation
- existing question-level "Response required." rendering
- scroll/focus callbacks
- navigation/debug logic unless absolutely required for compilation
This task is ONLY about the generic PANEL-LEVEL aggregate validation.
==================================================
INITIAL LOAD / SUBMIT BEHAVIOR
==================================================
Do not introduce validation on initial Audit load if the existing behavior
does not already do that.
Panel-level "Response required." should reflect the existing validation
lifecycle.
Do not change when validation is triggered.
Only fix HOW the panel-level state is calculated after validation occurs.
==================================================
IMPORTANT EDGE CASE
==================================================
If a panel has:
Q1 = answered
Q2 = unanswered
Q3 = answered
Q4 = unanswered
The panel MUST show:
Response required.
Even though most questions are answered.
If Q2 is answered but Q4 is still unanswered:
The panel MUST STILL show:
Response required.
Only after Q4 is answered should the panel-level message disappear.
==================================================
CROSS-AUDIT REQUIREMENT
==================================================
This solution must work across ALL audit types.
Do not test only the current audit.
If multiple Audit types/configurations are available, test at least
2–3 different audit structures.
The expected behavior must remain identical for every audit:
ANY unanswered required descendant
→ Panel shows "Response required."
ALL required descendants answered
→ Panel hides "Response required."
No additional configuration should be required for individual audits.
==================================================
VERIFICATION
==================================================
After making the change:
1. Build the application.
2. Confirm the build succeeds without new TypeScript/template errors.
3. Open an audit containing multiple generic Panels.
4. Submit with multiple unanswered required questions.
5. Confirm every affected Panel shows its own panel-level
"Response required."
6. In "Past Medical History and Review of Systems (ROS)", answer only
1 question.
7. Confirm the panel-level "Response required." STILL remains if other
required questions are unanswered.
8. Answer another question.
9. Confirm the panel-level message STILL remains while at least one
required descendant is unanswered.
10. Answer the final unanswered required question.
11. Confirm the panel-level "Response required." disappears.
12. Confirm each individual unanswered question continues showing its own
question-level "Response required."
13. Test a PanelDynamic.
14. Test nested Panels.
15. Test another Audit type/configuration.
16. Confirm no navigation/focus behavior was changed.
==================================================
FINAL RESPONSE REQUIRED
==================================================
Do NOT simply say "fixed".
After implementation, report:
1. The exact existing validation logic that caused the inconsistency.
2. Why the panel-level error was disappearing after answering one child.
3. Which function/file was changed.
4. The minimal code change made.
5. How the new logic determines the aggregate panel state.
6. Confirmation that PanelDynamic and nested Panels are supported.
7. Confirmation that the implementation is generic across ALL Audit types.
8. Confirmation that navigation/focus/getExactQuestionElement() was not
modified.
9. Build result.
10. Test results for:
- multiple unanswered questions
- answering one child
- answering all children
- nested panels
- PanelDynamic
- another Audit type
IMPORTANT:
Do not modify unrelated code.
Do not create audit-specific or panel-specific conditions.
Do not hardcode any names or IDs.
Make the smallest generic change that fixes the actual root cause.