Skip to content

Commit 55b9ae1

Browse files
updated survey-library docs [azurepipelines skip]
1 parent 244c7ea commit 55b9ae1

File tree

2 files changed

+90
-65
lines changed

2 files changed

+90
-65
lines changed

docs/design-survey-conditional-logic.md

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,47 +55,59 @@ Certain question types can contain multiple values. Use a dot symbol to access a
5555
<tbody>
5656
<tr>
5757
<td><a href="/Documentation/Library?id=questionmultipletextmodel">Multiple Textboxes</a></td>
58-
<td><code>{questionname.itemname}</code></td>
58+
<td><code>{qid.itemid}</code></td>
5959
</tr>
6060
<tr>
6161
<td><a href="/Documentation/Library?id=questionmatrixmodel">Single-Select Matrix</a></td>
62-
<td><code>{questionname.rowname}</code></td>
62+
<td><code>{maxtrixid.rowid}</code></td>
6363
</tr>
6464
<tr>
6565
<td rowspan="2" style="vertical-align:middle"><a href="/Documentation/Library?id=questionmatrixdropdownmodel">Multi-Select Matrix</a></td>
66-
<td><code>{questionname.rowname.columnname}</code></td>
66+
<td><code>{maxtrixid.rowid.columnid}</code></td>
6767
</tr>
6868
<tr>
69-
<td><code>{questionname-total.columnname}</code> (accesses a cell in the total row)</td>
69+
<td><code>{maxtrixid-total.columnid}</code> (accesses a cell in the total row)</td>
7070
</tr>
7171
</tbody>
7272
</table>
7373
</div>
7474

7575
[View Demo](https://surveyjs.io/form-library/examples/use-and-represent-complex-questions-in-expressions/ (linkStyle))
7676

77-
In question types whose value is an array, you can use zero-based indexes to access a specific item, question, or cell:
77+
In question types whose value is an array, you can use zero-based indexes to access a specific item, question, or matrix cell:
7878

7979
<div class="v2-class---doc-table-container">
8080
<table class="v2-class---doc-table-container__table">
8181
<thead>
8282
<tr>
8383
<th>Question Type</th>
8484
<th>Syntax</th>
85+
<th>Description</th>
8586
</tr>
8687
</thead>
8788
<tbody>
8889
<tr>
8990
<td><a href="https://surveyjs.io/form-library/documentation/api-reference/checkbox-question-model">Checkboxes</a>, <br><a href="https://surveyjs.io/form-library/documentation/api-reference/image-picker-question-model">Image Picker</a>, <br><a href="https://surveyjs.io/form-library/documentation/api-reference/multiple-text-entry-question-model">Multiple Textboxes</a>, <br><a href="https://surveyjs.io/form-library/documentation/api-reference/ranking-question-model">Ranking</a></td>
90-
<td style="vertical-align:middle"><code>{questionname[index]}</code></td>
91+
<td style="vertical-align:middle"><code>{qid[index]}</code></td>
92+
<td style="vertical-align:middle">Accesses a specific choice option or text box value.</td>
9193
</tr>
9294
<tr>
93-
<td><a href="/Documentation/Library?id=questionpaneldynamicmodel">Dynamic Panel</a></td>
94-
<td style="vertical-align:middle"><code>{dynamicpanelname[index].questionname}</code></td>
95+
<td style="vertical-align:middle" rowspan="2"><a href="/Documentation/Library?id=questionpaneldynamicmodel">Dynamic Panel</a></td>
96+
<td style="vertical-align:middle"><code>{dpanelid[index].qid}</code></td>
97+
<td>Accesses a question in a specific panel.</td>
9598
</tr>
9699
<tr>
97-
<td><a href="/Documentation/Library?id=questionmatrixdynamicmodel">Dynamic Matrix</a></td>
98-
<td style="vertical-align:middle"><code>{dynamicmatrixname[rowindex].columnname}</code></td>
100+
<td style="vertical-align:middle"><code>{dpanelid[-1].qid}</code><br><code>{dpanelid[-2].qid}</code><br>...</td>
101+
<td style="vertical-align:middle">Accesses a question in the last panel, the panel before the last, and so on.</td>
102+
</tr>
103+
<tr>
104+
<td rowspan="2" style="vertical-align:middle"><a href="/Documentation/Library?id=questionmatrixdynamicmodel">Dynamic Matrix</a></td>
105+
<td style="vertical-align:middle"><code>{dmatrixid[rowindex].columnid}</code></td>
106+
<td style="vertical-align:middle">Accesses a specific matrix cell.</td>
107+
</tr>
108+
<tr>
109+
<td style="vertical-align:middle"><code>{dmatrixid[-1].columnid}</code><br><code>{dmatrixid[-2].columnid}</code><br>...</td>
110+
<td style="vertical-align:middle">Accesses a cell in the last row, the row before the last, and so on.</td>
99111
</tr>
100112
</tbody>
101113
</table>
@@ -114,10 +126,18 @@ You can also use prefixes, such as `row`, `panel`, `parentPanel`, and `composite
114126
</thead>
115127
<tbody>
116128
<tr>
117-
<td rowspan="3" style="vertical-align:middle"><a href="https://github.com/form-library/documentation/api-reference/matrix-table-question-model">Single-Select Matrix</a>, <a href="https://github.com/form-library/documentation/api-reference/matrix-table-with-dropdown-list">Multi-Select Matrix</a>, <a href="https://github.com/form-library/documentation/api-reference/dynamic-matrix-table-question-model">Dynamic Matrix</a></td>
118-
<td><code>{row.columnname}</code></td>
129+
<td rowspan="5" style="vertical-align:middle"><a href="https://github.com/form-library/documentation/api-reference/matrix-table-question-model">Single-Select Matrix</a>, <a href="https://github.com/form-library/documentation/api-reference/matrix-table-with-dropdown-list">Multi-Select Matrix</a>, <a href="https://github.com/form-library/documentation/api-reference/dynamic-matrix-table-question-model">Dynamic Matrix</a></td>
130+
<td><code>{row.columnid}</code></td>
119131
<td>Accesses a cell in the same row.</td>
120132
</tr>
133+
<tr>
134+
<td><code>{prevRow.columnid}</code></td>
135+
<td>Accesses a cell in the previous row.</td>
136+
</tr>
137+
<tr>
138+
<td><code>{nextRow.columnid}</code></td>
139+
<td>Accesses a cell in the next row.</td>
140+
</tr>
121141
<tr>
122142
<td style="vertical-align:middle"><code>{rowName}</code></td>
123143
<td>Accesses the row name (the <code>value</code> property within objects in the <a href="https://surveyjs.io/form-library/documentation/api-reference/matrix-table-with-dropdown-list#rows"><code>rows</code></a> array). Use this placeholder if you need to distinguish between matrix rows.</td>
@@ -127,18 +147,26 @@ You can also use prefixes, such as `row`, `panel`, `parentPanel`, and `composite
127147
<td>Accesses the row title (the <code>text</code> property within objects in the <a href="https://surveyjs.io/form-library/documentation/api-reference/matrix-table-with-dropdown-list#rows"><code>rows</code></a> array).</td>
128148
</tr>
129149
<tr>
130-
<td rowspan="2" style="vertical-align:middle"><a href="/form-library/documentation/api-reference/dynamic-panel-model">Dynamic Panel</a></td>
131-
<td><code>{panel.questionname}</code></td>
132-
<td>Accesses a question within the same panel.</td>
150+
<td rowspan="4" style="vertical-align:middle"><a href="/form-library/documentation/api-reference/dynamic-panel-model">Dynamic Panel</a></td>
151+
<td><code>{panel.qid}</code></td>
152+
<td>Accesses a question in the same panel.</td>
153+
</tr>
154+
<tr>
155+
<td><code>{prevPanel.qid}</code></td>
156+
<td>Accesses a question in the previous panel.</td>
157+
</tr>
158+
<tr>
159+
<td><code>{nextPanel.qid}</code></td>
160+
<td>Accesses a question in the next panel.</td>
133161
</tr>
134162
<tr>
135-
<td style="vertical-align:middle"><code>{parentPanel.questionname}</code></td>
136-
<td>Accesses a question within a parent Dynamic Panel.<br>Applies when one Dynamic Panel question is nested in another.</td>
163+
<td style="vertical-align:middle"><code>{parentPanel.qid}</code></td>
164+
<td>Accesses a question in a parent Dynamic Panel.<br>Applies when one Dynamic Panel question is nested in another.</td>
137165
</tr>
138166
<tr>
139167
<td><a href="/form-library/documentation/customize-question-types/create-composite-question-types">Composite questions</a></td>
140-
<td><code>{composite.questionname}</code></td>
141-
<td>Accesses a question within the same composite question.</td>
168+
<td style="vertical-align:middle"><code>{composite.qid}</code></td>
169+
<td>Accesses a question in the same composite question.</td>
142170
</tr>
143171
</tbody>
144172
</table>

docs/how-to-save-and-restore-incomplete-survey.md

Lines changed: 43 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,32 @@ Respondents may not complete your survey in a single session. In this case, you
99

1010
## Restore Survey Progress from the `localStorage`
1111

12-
To save incomplete survey results locally, implement a function that stores them under a specified key in the `localStorage` (see the `saveSurveyData` function in the code below). Call this function within `SurveyModel`'s [`onValueChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onValueChanged) and [`onCurrentPageChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onCurrentPageChanged) event handlers to save the survey results each time users change a question value or switch between pages. When the survey is completed, submit final survey results to the server using the [`onComplete`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onComplete) event handler:
12+
To save incomplete results locally, implement functions that store [survey data](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#data) and [UI state](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#uiState) under specified keys in the `localStorage` (see the `saveSurveyData` and `saveSurveyUIState` functions in the code below). Call these functions inside the `SurveyModel`'s [`onValueChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onValueChanged) and [`onUIStateChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onUIStateChanged) event handlers to capture updates whenever users change a value or modify the UI (for example, expand/collapse a question box or switch pages). When the survey is completed, submit the final results to the server and remove them from the `localStorage` using the [`onComplete`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onComplete) event handler:
1313

1414
```js
1515
import { Model } from "survey-core";
1616

1717
const survey = new Model();
1818

19-
const STORAGE_ITEM_KEY = "my-survey";
19+
const STORAGE_ITEM_DATA_KEY = "my-survey-data";
20+
const STORAGE_ITEM_UI_STATE_KEY = "my-survey-state";
2021
const SURVEY_ID = /* ... Getting the survey ID ... */;
2122
const ENDPOINT_URL = "https://example.com/api/responses/" + SURVEY_ID;
2223

2324
fetch("https://example.com/api/surveys/" + SURVEY_ID)
2425
.then(response => response.json())
2526
.then(loadedSurvey => {
2627
survey.fromJSON(loadedSurvey.json);
27-
restoreSurveyData(survey);
28+
restoreSurvey(survey);
2829
})
2930
.catch(error => console.error(error));
3031

31-
function saveSurveyData(survey, options) {
32-
const data = survey.data;
33-
data.pageNo = survey.currentPageNo;
34-
if (options.name) {
35-
data.lastVisitedQuestion = options.name;
36-
}
37-
window.localStorage.setItem(storageItemKey, JSON.stringify(data));
32+
function saveSurveyData(survey) {
33+
window.localStorage.setItem(STORAGE_ITEM_DATA_KEY, JSON.stringify(survey.data));
34+
}
35+
36+
function saveSurveyUIState(survey) {
37+
window.localStorage.setItem(STORAGE_ITEM_UI_STATE_KEY, JSON.stringify(survey.uiState));
3838
}
3939

4040
function submitSurveyData(data) {
@@ -46,31 +46,29 @@ function submitSurveyData(data) {
4646
.then(response => response.json())
4747
.then(data => {
4848
console.log(data);
49-
window.localStorage.setItem(STORAGE_ITEM_KEY, "");
49+
window.localStorage.setItem(STORAGE_ITEM_DATA_KEY, "");
50+
window.localStorage.setItem(STORAGE_ITEM_UI_STATE_KEY, "");
5051
})
5152
.catch(error => console.error(error));
5253
}
5354

54-
function restoreSurveyData(survey) {
55-
const prevData = window.localStorage.getItem(STORAGE_ITEM_KEY) || null;
55+
function restoreSurvey(survey) {
56+
const prevData = window.localStorage.getItem(STORAGE_ITEM_DATA_KEY) || null;
5657
if (prevData) {
5758
const data = JSON.parse(prevData);
5859
survey.data = data;
59-
if (data.pageNo) {
60-
survey.currentPageNo = data.pageNo;
61-
}
62-
if (data.lastVisitedQuestion) {
63-
setTimeout(() => {
64-
survey.focusQuestion(data.lastVisitedQuestion);
65-
}, 500);
66-
}
60+
}
61+
const prevState = window.localStorage.getItem(STORAGE_ITEM_UI_STATE_KEY) || null;
62+
if (prevState) {
63+
const state = JSON.parse(prevState);
64+
survey.uiState = state;
6765
}
6866
}
6967

70-
// Save survey results and the last visited question name when users change a question value...
68+
// Save survey progress when users change a question value...
7169
survey.onValueChanged.add(saveSurveyData);
72-
// ... and switch to the next page
73-
survey.onCurrentPageChanged.add(saveSurveyData);
70+
// ... and when they modify the UI state (expand/collapse a question box or switch pages)
71+
survey.onUIStateChanged.add(saveSurveyUIState);
7472

7573
// Submit final survey results after the survey is completed
7674
survey.onComplete.add((survey) => {
@@ -86,13 +84,16 @@ survey.onComplete.add((survey) => {
8684
8785
## Restore Survey Progress from a Database
8886

89-
To save incomplete results in a database, submit them to your server each time users change a question value or switch between pages and when they complete the survey. Handle the [`onValueChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onValueChanged), [`onCurrentPageChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onCurrentPageChanged), and [`onComplete`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onComplete) events for this purpose.
87+
To save incomplete results in a database, submit them to your server each time users change a question value and when they complete the survey. Handle the [`onValueChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onValueChanged) and [`onComplete`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onComplete) to trigger these updates.
88+
89+
Saving the UI state on a server usually isn't practical because it represents device-specific UI preferences, such as which questions are expanded or which page the respondent last viewed. These preferences are relevant only within the current browser session and do not affect actual survey results. For this reason, UI state is better stored locally using the `localStorage`. To do this, handle the [`onUIStateChanged`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onUIStateChanged) event.
9090

9191
```js
9292
import { Model } from "survey-core";
9393

9494
const survey = new Model();
9595

96+
const STORAGE_ITEM_UI_STATE_KEY = "my-survey-state";
9697
const SURVEY_ID = /* ... Getting the survey ID ... */
9798
const USER_ID = /* ... Getting the user ID ... */
9899
const ENDPOINT_URL = "https://example.com/api/responses/" + SURVEY_ID + "/" + USER_ID;
@@ -101,17 +102,16 @@ fetch("https://example.com/api/surveys/" + SURVEY_ID)
101102
.then(response => response.json())
102103
.then(loadedSurvey => {
103104
survey.fromJSON(loadedSurvey.json);
104-
restoreSurveyData(survey);
105+
restoreSurvey(survey);
105106
})
106107
.catch(error => console.error(error));
107108

108-
function saveSurveyData(survey, options) {
109-
const data = survey.data;
110-
data.pageNo = survey.currentPageNo;
111-
if (options.name) {
112-
data.lastVisitedQuestion = options.name;
113-
}
114-
submitSurveyData(data);
109+
function saveSurveyData(survey) {
110+
submitSurveyData(survey.data);
111+
}
112+
113+
function saveSurveyUIState(survey) {
114+
window.localStorage.setItem(STORAGE_ITEM_UI_STATE_KEY, JSON.stringify(survey.uiState));
115115
}
116116

117117
function submitSurveyData(data) {
@@ -125,32 +125,29 @@ function submitSurveyData(data) {
125125
.catch(error => console.error(error));
126126
}
127127

128-
function restoreSurveyData(survey) {
128+
function restoreSurvey(survey) {
129129
fetch(ENDPOINT_URL)
130130
.then(response => response.json())
131131
.then(prevData => {
132132
if (prevData) {
133133
const data = JSON.parse(prevData);
134134
survey.data = data;
135-
if (data.pageNo) {
136-
survey.currentPageNo = data.pageNo;
137-
}
138-
if (data.lastVisitedQuestion) {
139-
setTimeout(() => {
140-
survey.focusQuestion(data.lastVisitedQuestion);
141-
}, 500);
142-
}
135+
}
136+
const prevState = window.localStorage.getItem(STORAGE_ITEM_UI_STATE_KEY) || null;
137+
if (prevState) {
138+
const state = JSON.parse(prevState);
139+
survey.uiState = state;
143140
}
144141
})
145142
.catch(error => console.error(error));
146143
}
147144

148-
// Submit survey results when users change a question value...
145+
// Submit survey progess when users change a question value...
149146
survey.onValueChanged.add(saveSurveyData);
150-
// ... switch to the next page...
151-
survey.onCurrentPageChanged.add(saveSurveyData);
152-
// ... and complete the survey
147+
// ... and when they complete the survey
153148
survey.onComplete.add(saveSurveyData);
149+
// Store the UI state when users modify it
150+
survey.onUIStateChanged.add(saveSurveyUIState);
154151
```
155152

156153
## See Also

0 commit comments

Comments
 (0)