Introduction
This documentation covers files located at: Questionnaire Renderer
General Information
Der Questionnaire Renderer dient dazu fhir questionnaire zu rendern sowie vorhandene questionnaire response elemente darzustellen und zu bearbeiten. Da wir den Renderer von Grund auf gebaut haben und keine Library nutzen haben wir theoretisch die möglichkeit einfach eigene elemente zu rendern, die darstellung nach unserem Design einzubinden sowie auch die lokalisierung logik zu verwalten. Dadurch ist es aber sehr wichtig die schwierigkeiten und komplexität zu verstehene den die datenstruktur von fhir questionnaire und questionnaire response vorgibt.
Grundsätzlicher Aufbaue der beiden Datenkonstrukte
Der Questionnaire ist die Konfiguration des gesamten Formulares. Dabei werden zur Darstellung des Formulares alle gewünschten Elemente als Questionnaire Items konfiguriert.
FHIR Questionnaire Item Examples
In a FHIR Questionnaire, the item element is recursive. This allows for simple flat lists or complex hierarchical structures. Below are three common patterns used in clinical data capture.
1. Simple String Item
The most basic pattern. Use type: "string" for short, single-line text inputs.
{
"linkId": "patient-nickname",
"text": "Preferred Name / Nickname",
"type": "string",
"required": false
}
2. Group with Multiple Strings
Groups (type: "group") allow you to organize related questions under a single header. This is essential for UI rendering (e.g., sections or cards).
{
"linkId": "address-section",
"text": "Mailing Address",
"type": "group",
"item": [
{
"linkId": "street-address",
"text": "Street and House Number",
"type": "string"
},
{
"linkId": "city",
"text": "City",
"type": "string"
},
{
"linkId": "zip-code",
"text": "Zip Code",
"type": "string"
}
]
}
3. Nested String (Question-under-Question)
FHIR allows you to nest items inside other items that are not groups. This is often used for follow-up details. In many renderers, the child item only becomes relevant if the parent item has a value.
{
"linkId": "current-medication",
"text": "Are you currently taking any medication? If so, which one?",
"type": "string",
"item": [
{
"linkId": "dosage-instruction",
"text": "What is the prescribed dosage for this medication?",
"type": "string"
}
]
}
Das sieht auf den ersten Blick nach einer relativ einfach abzubildenden Struktur aus, die daraus entstehnde Response jedoch ist komplexer aufgebaut als man denkt.
When an item is nested inside another (like a follow-up question), the QuestionnaireResponse mirrors this hierarchy. The nested question appears inside the item property of the parent's answer.
This example shows a full QuestionnaireResponse with nested questions for Example 3.
{
"resourceType": "QuestionnaireResponse",
"status": "completed",
"item": [
{
"linkId": "current-medication",
"text": "Are you currently taking any medication? If so, which one?",
"answer": [
{
"valueString": "Lisinopril",
"item": [
{
"linkId": "dosage-instruction",
"text": "What is the prescribed dosage for this medication?",
"answer": [
{
"valueString": "10mg once daily"
}
]
}
]
}
]
}
]
}
Notice that the nested linkId: "dosage-instruction" is placed inside the answer object of the parent. This reinforces that the dosage is directly related to the specific medication "Lisinopril".
Repetition of Items
The complexity of rendering a FHIR-based form primarily arises from the ability to repeat items. This feature, controlled by a simple repeats: true boolean flag, allows users to fill out a field or an entire group multiple times.
The Structural Complexity
The challenge begins with the fact that repeated instances only exist within the QuestionnaireResponse. Since child elements are nested directly within their parent's answers, they are duplicated in the response as well. This leads to several critical structural differences:
- Non-Unique linkIds: While
linkIdis unique within the Questionnaire (the schema), it is no longer unique within the Response (the instance) if items repeat. - Sparse Trees: A
QuestionnaireResponsedoes not contain the full tree structure of the Questionnaire; it only includes items that have been populated with data. - Shifted Nesting: The Response uses a different nesting logic than the Questionnaire to maintain the association between specific answers and their nested sub-elements.
Key Considerations for Implementation
When documenting your rendering logic, keep the following points in mind:
- Questionnaire Structure: Every
linkIdis unique, and each item definition exists only once. - Response Density: The Response is often incomplete, as it omits unanswered items.
- Cardinality: The Response can contain multiple items with the same
linkId, breaking the uniqueness found in the schema. - Hierarchical Alignment: The Response structure changes to accommodate repetitions and ensure that nested elements are correctly mapped to their specific parent answers.
Conclusion for Frontend Rendering
Effectively rendering a form requires a hybrid approach. The frontend must combine the Questionnaire configuration (the "what") with the QuestionnaireResponse (the "how many"). Even if a response does not exist yet, the form must be capable of dynamically altering its rendered structure as the user interacts with repeating elements.
The linkId of the items serves as the unique identifier. It is mandatory to set this value and ensure it is unique within the entire Questionnaire configuration.
Duplicate IDs will result in incorrect form rendering and data corruption.
Questionnaire and QuestionnaireResponse Relationship
The following high-level diagram illustrates the relationships and dependencies described above:
Our Questionnaire Renderer Architecture
The different layers of our renderer are illustrated in this diagram. Each element is described in technical detail on its respective page.