Skip to content

Commit 459541b

Browse files
committed
Add pre-populated questionnaire matches
1 parent 51451a2 commit 459541b

8 files changed

Lines changed: 909 additions & 13 deletions

File tree

skills/lforms-fhir-questionnaire.md

Lines changed: 414 additions & 0 deletions
Large diffs are not rendered by default.

src/app/benefits-demo/clinical-forms/clinical-forms.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ <h3>Submitting ICSR Report...</h3>
9595
<app-questionnaire-form
9696
[questionnaire]="getQuestionnaire(selectedForm)"
9797
[questionnaireId]="selectedForm"
98+
[patientId]="patient?.id ?? null"
9899
(formSubmitted)="onQuestionnaireSubmitted($event)"
99100
(formCancelled)="onFormCancelled()">
100101
</app-questionnaire-form>

src/app/benefits-demo/clinical-record/clinical-record.component.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,6 @@ export class ClinicalRecordComponent implements OnInit, OnDestroy, AfterViewInit
450450
}
451451

452452
async loadClinicalData(patientId: string): Promise<void> {
453-
console.trace(`[loadClinicalData] called for patient ${patientId}`);
454453
if (this.patientService.getCurrentPersistenceMode() === 'fhir') {
455454
this.isLoadingClinicalData = true;
456455

src/app/benefits-demo/questionnaire-form/questionnaire-form.component.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,26 @@
6060
font-weight: 500;
6161
}
6262

63+
.pre-populated-badge {
64+
display: inline-flex;
65+
align-items: center;
66+
gap: 4px;
67+
padding: 3px 10px;
68+
border-radius: 20px;
69+
font-size: 0.8rem;
70+
font-weight: 500;
71+
background-color: #e8f5e9;
72+
color: #2e7d32;
73+
border: 1px solid #a5d6a7;
74+
}
75+
76+
.pre-populated-badge mat-icon {
77+
font-size: 15px;
78+
width: 15px;
79+
height: 15px;
80+
line-height: 15px;
81+
}
82+
6383
.lforms-container {
6484
margin: 24px 0;
6585
min-height: 200px;

src/app/benefits-demo/questionnaire-form/questionnaire-form.component.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ <h3>{{ questionnaire.title }}</h3>
1212
@if (questionnaire.version) {
1313
<span class="version-info">v{{ questionnaire.version }}</span>
1414
}
15+
@if (isPrePopulated) {
16+
<span class="pre-populated-badge">
17+
<mat-icon>auto_fix_high</mat-icon>
18+
Pre-populated from patient record
19+
</span>
20+
}
1521
</div>
1622
</div>
1723
}

src/app/benefits-demo/questionnaire-form/questionnaire-form.component.ts

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Component, Input, OnChanges, SimpleChanges, EventEmitter, Output, AfterViewInit, ChangeDetectorRef } from '@angular/core';
2+
import { SdcPopulationService } from '../../services/sdc-population.service';
3+
import { FhirService } from '../../services/fhir.service';
24

35
declare var LForms: any;
46

@@ -11,14 +13,20 @@ declare var LForms: any;
1113
export class QuestionnaireFormComponent implements OnChanges, AfterViewInit {
1214
@Input() questionnaire: any = null;
1315
@Input() questionnaireId: string = '';
16+
@Input() patientId: string | null = null;
1417
@Output() formSubmitted = new EventEmitter<any>();
1518
@Output() formCancelled = new EventEmitter<void>();
1619

1720
formRendered = false;
21+
isPrePopulated = false;
1822
formContainerId = '';
1923
private lformsLoaded = false;
2024

21-
constructor(private cdr: ChangeDetectorRef) {
25+
constructor(
26+
private cdr: ChangeDetectorRef,
27+
private sdcPopulationService: SdcPopulationService,
28+
private fhirService: FhirService
29+
) {
2230
// Generate unique container ID for this component instance
2331
this.formContainerId = `questionnaire-form-${Math.random().toString(36).substr(2, 9)}`;
2432
// Load LForms library if not already loaded
@@ -63,7 +71,7 @@ export class QuestionnaireFormComponent implements OnChanges, AfterViewInit {
6371
document.head.appendChild(script);
6472
}
6573

66-
renderForm(): void {
74+
async renderForm(): Promise<void> {
6775
if (!this.questionnaire) {
6876
this.formRendered = false;
6977
return;
@@ -75,26 +83,50 @@ export class QuestionnaireFormComponent implements OnChanges, AfterViewInit {
7583
}
7684

7785
try {
78-
// Check if container exists
7986
const container = document.getElementById(this.formContainerId);
8087
if (!container) {
8188
this.formRendered = false;
8289
return;
8390
}
84-
85-
// Clear any existing form first
91+
8692
container.innerHTML = '';
87-
88-
// Render the questionnaire using LForms
89-
// Use setTimeout to ensure the container is fully cleared
93+
94+
let populatedQR: any = null;
95+
if (this.patientId) {
96+
try {
97+
populatedQR = this.sdcPopulationService.populate(this.questionnaire, this.patientId);
98+
} catch {
99+
// Pre-population failure must never block form rendering
100+
}
101+
}
102+
90103
setTimeout(() => {
91104
try {
92-
LForms.Util.addFormToPage(this.questionnaire, this.formContainerId);
105+
if (populatedQR) {
106+
// Merge approach: convert questionnaire to LForms internal format first,
107+
// then merge the QR into it before rendering. This is the correct LForms
108+
// API for pre-population — addFormToPage options do not apply QR answers.
109+
if (typeof LForms.Util.setFHIRContext === 'function') {
110+
LForms.Util.setFHIRContext({ baseUrl: this.fhirService.getBaseUrl() });
111+
}
112+
const lfData = LForms.Util.convertFHIRQuestionnaireToLForms(this.questionnaire, 'R4');
113+
const merged = LForms.Util.mergeFHIRDataIntoLForms('QuestionnaireResponse', populatedQR, lfData, 'R4');
114+
LForms.Util.addFormToPage(merged, this.formContainerId);
115+
} else {
116+
LForms.Util.addFormToPage(this.questionnaire, this.formContainerId);
117+
}
93118
this.formRendered = true;
94-
// Trigger change detection to update the view
119+
this.isPrePopulated = !!populatedQR;
95120
this.cdr.detectChanges();
96121
} catch (innerError) {
97-
this.formRendered = false;
122+
// If merge/render fails, fall back to plain render without pre-population
123+
try {
124+
LForms.Util.addFormToPage(this.questionnaire, this.formContainerId);
125+
this.formRendered = true;
126+
} catch {
127+
this.formRendered = false;
128+
}
129+
this.isPrePopulated = false;
98130
this.cdr.detectChanges();
99131
}
100132
}, 100);

0 commit comments

Comments
 (0)