@planning-inspectorate/dynamic-forms 3.20.5 → 3.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -0
- package/docs/Dynamic Sections.md +47 -0
- package/docs/Getting Started.md +8 -2
- package/package.json +1 -1
- package/src/components/boolean/question.d.ts +1 -1
- package/src/components/boolean/question.js +1 -1
- package/src/components/date/question.d.ts +1 -1
- package/src/components/date/question.js +1 -1
- package/src/components/date-period/question.d.ts +1 -1
- package/src/components/date-period/question.js +1 -1
- package/src/components/date-time/question.d.ts +1 -1
- package/src/components/date-time/question.js +1 -1
- package/src/components/manage-list/question.d.ts.map +1 -1
- package/src/components/manage-list/question.js +5 -0
- package/src/components/manage-list/question.test.js +3 -1
- package/src/components/multi-field-input/question.d.ts.map +1 -1
- package/src/components/multi-field-input/question.js +8 -6
- package/src/components/multi-field-input/question.test.js +126 -213
- package/src/components/single-line-input/index.njk +4 -0
- package/src/components/single-line-input/question.d.ts +2 -0
- package/src/components/single-line-input/question.d.ts.map +1 -1
- package/src/components/single-line-input/question.js +4 -0
- package/src/components/single-line-input/question.test.js +6 -0
- package/src/components/text-entry-redact/question.d.ts.map +1 -1
- package/src/components/text-entry-redact/question.js +3 -1
- package/src/components/text-entry-redact/question.test.js +9 -0
- package/src/components/unit-option-entry/question.d.ts +1 -1
- package/src/components/unit-option-entry/question.d.ts.map +1 -1
- package/src/components/unit-option-entry/question.js +4 -2
- package/src/components/unit-option-entry/question.test.js +9 -0
- package/src/controller.d.ts +15 -3
- package/src/controller.d.ts.map +1 -1
- package/src/controller.js +19 -11
- package/src/controller.test.js +182 -153
- package/src/dynamic-section.d.ts +40 -0
- package/src/dynamic-section.d.ts.map +1 -0
- package/src/dynamic-section.js +51 -0
- package/src/dynamic-section.test.js +113 -0
- package/src/index.d.ts +2 -1
- package/src/index.js +2 -1
- package/src/index.test.js +3 -0
- package/src/journey/journey.d.ts +10 -0
- package/src/journey/journey.d.ts.map +1 -1
- package/src/journey/journey.js +15 -0
- package/src/lib/answer-utils.d.ts +22 -0
- package/src/lib/answer-utils.d.ts.map +1 -0
- package/src/lib/answer-utils.js +34 -0
- package/src/{components/manage-list/utils.test.js → lib/answer-utils.test.js} +9 -11
- package/src/lib/session-answer-store.d.ts.map +1 -1
- package/src/lib/session-answer-store.js +14 -6
- package/src/lib/session-answer-store.test.js +43 -0
- package/src/middleware/redirect-to-unanswered-question.d.ts.map +1 -1
- package/src/middleware/redirect-to-unanswered-question.js +4 -3
- package/src/middleware/redirect-to-unanswered-question.test.js +32 -0
- package/src/questions/options-question.js +1 -1
- package/src/questions/question.d.ts +8 -3
- package/src/questions/question.d.ts.map +1 -1
- package/src/questions/question.js +16 -6
- package/src/questions/question.test.js +19 -0
- package/src/section.d.ts +19 -0
- package/src/section.d.ts.map +1 -1
- package/src/section.js +50 -9
- package/src/section.test.js +9 -0
- package/test/dynamic-journey.test.js +372 -0
- package/typedefs/question-props.d.ts +3 -1
- package/typedefs/question-types.d.ts +3 -0
- package/src/components/manage-list/utils.d.ts +0 -18
- package/src/components/manage-list/utils.d.ts.map +0 -1
- package/src/components/manage-list/utils.js +0 -35
package/README.md
CHANGED
|
@@ -82,6 +82,100 @@ The controllers available are:
|
|
|
82
82
|
| buildSave | Returns a controller to handle saving the answer and either redirecting to the next question or show any validation errors if present. Accepts a save function. |
|
|
83
83
|
| list/buildList | Renders a check-your-answers page showing all the answers, links to change any answer, and a button to submit the answers. |
|
|
84
84
|
|
|
85
|
+
#### Saving answers
|
|
86
|
+
|
|
87
|
+
The `buildSave` controller accepts a `SaveDataFn` which is passed the context required to save the answer(s). To save answers to session during a journey, a `SaveDataFn` implementation is provided called `saveDataToSession`.
|
|
88
|
+
|
|
89
|
+
For other use cases, write a custom `SaveDataFn`. A basic implementation (if you are not using ManageList or DynamicSection) needs to save the answers passed in as `data.answers`, which is an object whose keys are the question field names, and the values are the answers. For example:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const update: SaveDataFn = async ({data}) => {
|
|
93
|
+
const answers = data.answers;
|
|
94
|
+
|
|
95
|
+
console.log('saving', answers);
|
|
96
|
+
|
|
97
|
+
// TODO: map to database
|
|
98
|
+
// TODO: write to database
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
To support `ManageList` questions as well, handle the `isManageListItem`, `manageListQuestionFieldName`, `manageListItemRemove` parameters. For example:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const update: SaveDataFn = async ({data, req, isManageListItem, manageListQuestionFieldName, manageListItemRemove}) => {
|
|
106
|
+
if (isManageListItem) {
|
|
107
|
+
const update = {
|
|
108
|
+
id: req.params.manageListItemId,
|
|
109
|
+
...data.answers
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
console.log('saving', update);
|
|
113
|
+
// TODO: map to database
|
|
114
|
+
// TODO: write to database
|
|
115
|
+
return;
|
|
116
|
+
} else if (manageListItemRemove) {
|
|
117
|
+
const id = req.params.manageListItemId;
|
|
118
|
+
// identify which type of item it is via the field name
|
|
119
|
+
const type = manageListQuestionFieldName;
|
|
120
|
+
console.log('removing item', {id, type});
|
|
121
|
+
// TODO: delete from database
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const answers = data.answers;
|
|
125
|
+
|
|
126
|
+
console.log('saving', answers);
|
|
127
|
+
|
|
128
|
+
// TODO: map to database
|
|
129
|
+
// TODO: write to database
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
To support `DynamicSection`, handle `isDynamicSection`, `dynamicSectionFieldName`, and `dynamicSectionId`. The implementation is very similar to the manage lists and the logic can be combined. For example:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const update: SaveDataFn = async ({
|
|
137
|
+
data,
|
|
138
|
+
req,
|
|
139
|
+
isManageListItem,
|
|
140
|
+
manageListQuestionFieldName,
|
|
141
|
+
manageListItemRemove,
|
|
142
|
+
isDynamicSection,
|
|
143
|
+
dynamicSectionFieldName,
|
|
144
|
+
dynamicSectionId
|
|
145
|
+
}) => {
|
|
146
|
+
if (isManageListItem || isDynamicSection) {
|
|
147
|
+
// manage list and dynamic sections can be handled the same, just with different properties
|
|
148
|
+
// for the fieldName and item id
|
|
149
|
+
const fieldName = isManageListItem ? manageListQuestionFieldName : dynamicSectionFieldName;
|
|
150
|
+
const itemId = isManageListItem ? req.params.manageListItemId : dynamicSectionId;
|
|
151
|
+
|
|
152
|
+
const update = {
|
|
153
|
+
id: itemId,
|
|
154
|
+
...data.answers
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
console.log('saving', update);
|
|
158
|
+
// TODO: map to database
|
|
159
|
+
// TODO: write to database
|
|
160
|
+
return;
|
|
161
|
+
} else if (manageListItemRemove) {
|
|
162
|
+
const id = req.params.manageListItemId;
|
|
163
|
+
// identify which type of item it is via the field name
|
|
164
|
+
const type = manageListQuestionFieldName;
|
|
165
|
+
console.log('removing item', {id, type});
|
|
166
|
+
// TODO: delete from database
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const answers = data.answers;
|
|
170
|
+
|
|
171
|
+
console.log('saving', answers);
|
|
172
|
+
|
|
173
|
+
// TODO: map to database
|
|
174
|
+
// TODO: write to database
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
|
|
85
179
|
### Conditions
|
|
86
180
|
|
|
87
181
|
Conditions are used to show/hide questions based on the answers to other questions. There are fluent methods on a Section
|
|
@@ -221,6 +315,12 @@ formatSummaryValue: ({ formattedAnswer, journey }) => {
|
|
|
221
315
|
|
|
222
316
|
> **Note:** `formattedAnswer` is already escaped by dynamic-forms; you are responsible for escaping any additional user-controlled values you include (for example `answer` or values read from `journey.response.answers`).
|
|
223
317
|
|
|
318
|
+
### Other features
|
|
319
|
+
|
|
320
|
+
See documentation in [docs](./docs), including:
|
|
321
|
+
|
|
322
|
+
* [Dynamic Sections](./docs/Dynamic%20Sections.md)
|
|
323
|
+
|
|
224
324
|
## Contributing
|
|
225
325
|
|
|
226
326
|
When contributing to this package, ensure changes are generic and not service-specific. Speak to the R&D devs if you are not sure. Prefer configuration over hardcoding values, and ensure the code is well documented.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Dynamic Sections
|
|
2
|
+
|
|
3
|
+
Use a dynamic section for sections which are generated from an array of objects.
|
|
4
|
+
|
|
5
|
+
This can be useful for adding a section for each entry in a ManageList, or each row in a database. The controller logic, when encountering a DynamicSection, will check for answers within `journeyResponse.answers[section.fieldName]` which is expected to be an array, and it will look for an object with an `id` property matching the sections' segment.
|
|
6
|
+
|
|
7
|
+
For example, considering a dynamic section for a Person object:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
function createPersonSection(person) {
|
|
11
|
+
return new DynamicSection(person.name, person.id, 'people').addQuestion(questions.name);
|
|
12
|
+
// ... other questions
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then the answers object should be of the form:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
answers = {
|
|
20
|
+
myField: 'some answer', // a normal question field
|
|
21
|
+
people: [
|
|
22
|
+
// dynamic section fields
|
|
23
|
+
{ id: 'person-id-1', name: 'Grogu' },
|
|
24
|
+
{ id: 'person-id-2', name: 'Mando' }
|
|
25
|
+
]
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Saving data
|
|
30
|
+
|
|
31
|
+
When using with `buildSave`, be sure to handle the parameters: `isDynamicSection`, `dynamicSectionId`,`dynamicSectionFieldName`. The implementation `buildSaveDataToSession` (in `session-answer-store.js`) may be a useful reference.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
const buildSaveFn: SaveDataFn = async (params) => {
|
|
35
|
+
if (params.isDynamicSection) {
|
|
36
|
+
// saving a response within a dynamic section
|
|
37
|
+
const itemId = params.dynamicSectionId;
|
|
38
|
+
const listType = params.dynamicSectionFieldName;
|
|
39
|
+
|
|
40
|
+
// some logic to save the data for this item
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Conditions
|
|
46
|
+
|
|
47
|
+
Question conditions can only access other questions within the section.
|
package/docs/Getting Started.md
CHANGED
|
@@ -78,7 +78,7 @@ Dynamic forms requires two templates to work for rendering questions and renderi
|
|
|
78
78
|
### Journey (or question) template
|
|
79
79
|
|
|
80
80
|
The journey template is used for question pages. It must include a block called `dynQuestionContent`, and a block called `head` (which the default gov.uk template has).
|
|
81
|
-
It should also include the rendering of the errorSummary component. The path to this template is configured via the `journeyTemplate` property on a Journey.
|
|
81
|
+
It should also include the rendering of the errorSummary component, and optionally the back link. The path to this template is configured via the `journeyTemplate` property on a Journey.
|
|
82
82
|
|
|
83
83
|
For example:
|
|
84
84
|
|
|
@@ -87,7 +87,13 @@ e.g.
|
|
|
87
87
|
```nunjucks
|
|
88
88
|
{% extends "govuk/template.njk" %}
|
|
89
89
|
|
|
90
|
-
{%
|
|
90
|
+
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
|
|
91
|
+
{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
|
|
92
|
+
|
|
93
|
+
{% block containerStart %}
|
|
94
|
+
{% if backLink %}
|
|
95
|
+
{{ govukBackLink({ href: backLink }) }}
|
|
96
|
+
{% endif %}
|
|
91
97
|
{% if errorSummary %}
|
|
92
98
|
<div class="govuk-grid-row">
|
|
93
99
|
<div class="govuk-grid-column-two-thirds">
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@ export class BooleanQuestion extends RadioQuestion {
|
|
|
17
17
|
/**
|
|
18
18
|
* Get the data to save from the request, returns an object of answers
|
|
19
19
|
* @param {import('express').Request} req
|
|
20
|
-
* @param {JourneyResponse} journeyResponse - current journey response
|
|
20
|
+
* @param {JourneyResponse} journeyResponse - current journey response
|
|
21
21
|
* @returns {Promise<{ answers: Record<string, unknown> }>}
|
|
22
22
|
*/ getDataToSave(req: import("express").Request, journeyResponse: JourneyResponse): Promise<{
|
|
23
23
|
answers: Record<string, unknown>;
|
|
@@ -97,7 +97,7 @@ export class BooleanQuestion extends RadioQuestion {
|
|
|
97
97
|
/**
|
|
98
98
|
* Get the data to save from the request, returns an object of answers
|
|
99
99
|
* @param {import('express').Request} req
|
|
100
|
-
* @param {JourneyResponse} journeyResponse - current journey response
|
|
100
|
+
* @param {JourneyResponse} journeyResponse - current journey response
|
|
101
101
|
* @returns {Promise<{ answers: Record<string, unknown> }>}
|
|
102
102
|
*/ //eslint-disable-next-line no-unused-vars -- journeyResponse kept for other questions to use
|
|
103
103
|
async getDataToSave(req, journeyResponse) {
|
|
@@ -10,7 +10,7 @@ export class DateQuestion extends Question {
|
|
|
10
10
|
/**
|
|
11
11
|
* Get the data to save from the request, returns an object of answers
|
|
12
12
|
* @param {import('express').Request} req
|
|
13
|
-
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
13
|
+
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
14
14
|
* @returns {Promise.<Object>}
|
|
15
15
|
*/ getDataToSave(req: import("express").Request, journeyResponse: import("#journey-response").JourneyResponse): Promise<Object>;
|
|
16
16
|
answerForViewModel(answers: any, isPayload: any): {
|
|
@@ -29,7 +29,7 @@ export class DateQuestion extends Question {
|
|
|
29
29
|
/**
|
|
30
30
|
* Get the data to save from the request, returns an object of answers
|
|
31
31
|
* @param {import('express').Request} req
|
|
32
|
-
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
32
|
+
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
33
33
|
* @returns {Promise.<Object>}
|
|
34
34
|
*/ //eslint-disable-next-line no-unused-vars -- journeyResponse kept for other questions to use
|
|
35
35
|
async getDataToSave(req, journeyResponse) {
|
|
@@ -19,7 +19,7 @@ export class DatePeriodQuestion extends Question {
|
|
|
19
19
|
/**
|
|
20
20
|
* Get the data to save from the request, returns an object of answers
|
|
21
21
|
* @param {import('express').Request} req
|
|
22
|
-
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
22
|
+
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
23
23
|
* @returns {Promise.<Object>}
|
|
24
24
|
*/ getDataToSave(req: import("express").Request, journeyResponse: import("#journey-response").JourneyResponse): Promise<Object>;
|
|
25
25
|
answerForViewModel(answers: any, isPayload: any): {
|
|
@@ -54,7 +54,7 @@ export class DatePeriodQuestion extends Question {
|
|
|
54
54
|
/**
|
|
55
55
|
* Get the data to save from the request, returns an object of answers
|
|
56
56
|
* @param {import('express').Request} req
|
|
57
|
-
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
57
|
+
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
58
58
|
* @returns {Promise.<Object>}
|
|
59
59
|
*/ //eslint-disable-next-line no-unused-vars -- journeyResponse kept for other questions to use
|
|
60
60
|
async getDataToSave(req, journeyResponse) {
|
|
@@ -10,7 +10,7 @@ export class DateTimeQuestion extends Question {
|
|
|
10
10
|
/**
|
|
11
11
|
* Get the data to save from the request, returns an object of answers
|
|
12
12
|
* @param {import('express').Request} req
|
|
13
|
-
* @param {JourneyResponse} journeyResponse - current journey response
|
|
13
|
+
* @param {JourneyResponse} journeyResponse - current journey response
|
|
14
14
|
* @returns {Promise.<Object>}
|
|
15
15
|
*/ getDataToSave(req: import("express").Request, journeyResponse: JourneyResponse): Promise<Object>;
|
|
16
16
|
answerForViewModel(answers: any, isPayload: any): {
|
|
@@ -38,7 +38,7 @@ export class DateTimeQuestion extends Question {
|
|
|
38
38
|
/**
|
|
39
39
|
* Get the data to save from the request, returns an object of answers
|
|
40
40
|
* @param {import('express').Request} req
|
|
41
|
-
* @param {JourneyResponse} journeyResponse - current journey response
|
|
41
|
+
* @param {JourneyResponse} journeyResponse - current journey response
|
|
42
42
|
* @returns {Promise.<Object>}
|
|
43
43
|
*/ //eslint-disable-next-line no-unused-vars -- journeyResponse kept for other questions to use
|
|
44
44
|
async getDataToSave(req, journeyResponse) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["question.js"],"names":[],"mappings":"AAKA;;;;;;GAMG;AAEH;IAOC;;OAEG;IACH,oBAFW,OAAO,+BAA+B,EAAE,wBAAwB,EAe1E;IAcD,wCAEC;
|
|
1
|
+
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["question.js"],"names":[],"mappings":"AAKA;;;;;;GAMG;AAEH;IAOC;;OAEG;IACH,oBAFW,OAAO,+BAA+B,EAAE,wBAAwB,EAe1E;IAcD,wCAEC;IA8DD;;;;OAMC;IAED;;OAEG;IACH,+BAkBC;IAED,4EAQC;IAoCD,yDAEC;IATD,kDAKC;;CAKD;;;;;;mBAzLa,MAAM;;;;;;;;;;;;;;yBAPK,WAAW"}
|
|
@@ -85,6 +85,11 @@ export class ManageListQuestion extends Question {
|
|
|
85
85
|
}
|
|
86
86
|
const mockJourney = {
|
|
87
87
|
getCurrentQuestionUrl() {},
|
|
88
|
+
responseForSection() {
|
|
89
|
+
// this function is already passed the array-item
|
|
90
|
+
// call to formatAnswerForSummary may use responseForSection so we implement here
|
|
91
|
+
return this.response;
|
|
92
|
+
},
|
|
88
93
|
response: {
|
|
89
94
|
answers: answer
|
|
90
95
|
}
|
|
@@ -54,7 +54,9 @@ describe('components/manage-list/question', () => {
|
|
|
54
54
|
const innerQ2 = {
|
|
55
55
|
url: 'second-question',
|
|
56
56
|
title: 'Q 2',
|
|
57
|
-
formatAnswerForSummary() {
|
|
57
|
+
formatAnswerForSummary(sectionSegment, journey) {
|
|
58
|
+
// simulate a question which may call responseForSection, such as multi field input
|
|
59
|
+
journey.responseForSection(sectionSegment);
|
|
58
60
|
return [{ value: 'mock answer 2' }];
|
|
59
61
|
}
|
|
60
62
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["question.js"],"names":[],"mappings":"AAIA;;GAEG;AACH;IACC;;OAEG;IACH,8CAFW,OAAO,+BAA+B,EAAE,6BAA6B,EAe/E;IAJC,kEAA8B;IAchC;;;;;;;;;;;;;;;QAOC;IA4CD;;;;;OAKG;IACH,uCAJW,MAAM,WACN,OAAO,UAAU,EAAE,OAAO,GACxB,OAAO,+BAA+B,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"question.d.ts","sourceRoot":"","sources":["question.js"],"names":[],"mappings":"AAIA;;GAEG;AACH;IACC;;OAEG;IACH,8CAFW,OAAO,+BAA+B,EAAE,6BAA6B,EAe/E;IAJC,kEAA8B;IAchC;;;;;;;;;;;;;;;QAOC;IA4CD;;;;;OAKG;IACH,uCAJW,MAAM,WACN,OAAO,UAAU,EAAE,OAAO,GACxB,OAAO,+BAA+B,EAAE,UAAU,EAAE,CAyChE;;CAsDD;;yBAxLwB,WAAW"}
|
|
@@ -44,7 +44,7 @@ export class MultiFieldInputQuestion extends Question {
|
|
|
44
44
|
/**
|
|
45
45
|
* Get the data to save from the request, returns an object of answers
|
|
46
46
|
* @param {import('express').Request} req
|
|
47
|
-
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
47
|
+
* @param {import('#journey-response').JourneyResponse} journeyResponse - current journey response
|
|
48
48
|
* @returns {Promise<{ answers: Record<string, unknown> }>}
|
|
49
49
|
*/ //eslint-disable-next-line no-unused-vars -- journeyResponse kept for other questions to use
|
|
50
50
|
async getDataToSave(req, journeyResponse) {
|
|
@@ -90,8 +90,10 @@ export class MultiFieldInputQuestion extends Question {
|
|
|
90
90
|
* @returns {import('#typedefs/question-types.d.ts').SummaryRow[]}
|
|
91
91
|
*/
|
|
92
92
|
formatAnswerForSummary(sectionSegment, journey) {
|
|
93
|
+
// get the response/answers for the section we're in - which might be a dynamic section
|
|
94
|
+
const response = journey.responseForSection(sectionSegment);
|
|
93
95
|
// Handle unanswered case - delegate to parent for notStartedText
|
|
94
|
-
if (this.#allQuestionsUnanswered(
|
|
96
|
+
if (this.#allQuestionsUnanswered(response)) {
|
|
95
97
|
return super.formatAnswerForSummary(sectionSegment, journey, null);
|
|
96
98
|
}
|
|
97
99
|
|
|
@@ -99,7 +101,7 @@ export class MultiFieldInputQuestion extends Question {
|
|
|
99
101
|
const defaultJoinString = this.isInManageListSection ? '\n' : '<br>';
|
|
100
102
|
|
|
101
103
|
let summaryDetails = this.inputFields.reduce((accumulator, field) => {
|
|
102
|
-
const rawAnswer =
|
|
104
|
+
const rawAnswer = response.answers[field.fieldName];
|
|
103
105
|
if (rawAnswer === undefined || rawAnswer === null || rawAnswer === '') return accumulator;
|
|
104
106
|
|
|
105
107
|
const formatted = this.#formatFieldForSummary(rawAnswer, field, journey, sectionSegment);
|
|
@@ -159,11 +161,11 @@ export class MultiFieldInputQuestion extends Question {
|
|
|
159
161
|
|
|
160
162
|
/**
|
|
161
163
|
* checks whether any answers have been provided for input field questions
|
|
162
|
-
* @param {import('#journey').
|
|
164
|
+
* @param {import('#journey-response').JourneyResponse} response
|
|
163
165
|
* @returns {boolean}
|
|
164
166
|
*/
|
|
165
|
-
#allQuestionsUnanswered(
|
|
166
|
-
return this.inputFields.every((field) =>
|
|
167
|
+
#allQuestionsUnanswered(response) {
|
|
168
|
+
return this.inputFields.every((field) => response.answers[field.fieldName] === undefined);
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
/**
|