0% found this document useful (0 votes)
54 views322 pages

v2022 Scripting Manual Rev1

The Forsta v2022 Scripting Manual, published in January 2022, provides comprehensive guidance on Forsta Scripting and its features as of Build 2022.1.23. It includes information on scripting usage, types, variables, functions, and various methods, while also noting that new features may be introduced after the publication date.

Uploaded by

Nitish Sharma
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
54 views322 pages

v2022 Scripting Manual Rev1

The Forsta v2022 Scripting Manual, published in January 2022, provides comprehensive guidance on Forsta Scripting and its features as of Build 2022.1.23. It includes information on scripting usage, types, variables, functions, and various methods, while also noting that new features may be introduced after the publication date.

Uploaded by

Nitish Sharma
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 322

Forsta v2022

Forsta v2022 Scripting Manual Forsta Confidential

This is revision 1 of the Forsta v2022 Scripting Manual published in January 2022. The information herein describes
Forsta Scripting and its features as of Build nr. 2022.1.23. New features may be introduced into the product after this
date. Go to www.forsta.com or check “News” on the Customer Extranet for the latest updates.
Copyright © 2022 by Forsta. All Rights Reserved.
This document is intended only for registered Forsta clients. No part of the contents of this document may be
reproduced or transmitted in any form or by any means without the written permission of Forsta.
Forsta makes no representations or warranties regarding the contents of this manual, and specifically disclaims any
implied warranties of merchantability or fitness for any particular purpose. The information in this manual is subject to
change without notice.
The companies, names and data used or described in the examples herein are fictitious.

- ii -
Forsta Confidential Forsta v2022 Scripting Manual

Table of Contents
Table of Contents ................................................................................................................................ 3
What's New in this Revision? ........................................................................................................... 14
1. Introduction..................................................................................................................................... 1
1.1. JScript .NET Fast Mode............................................................................................................. 1
1.1.1. All Variables Must Be Declared. .......................................................................................... 2
1.1.2. Functions Become Constants ............................................................................................. 2
1.1.3. The arguments Object is not Available ................................................................................ 2
1.1.4. Using a Sorting Function in the sort Method (on Array) ....................................................... 2
2. Where is Scripting Used in Forsta? .............................................................................................. 4
2.1. Conditions ................................................................................................................................... 4
2.2. Filtering Answer Lists, Scales and Loops .................................................................................. 5
2.2.1. Code Masks and Scale Masks ............................................................................................ 5
2.2.2. Column and Question Masks ............................................................................................... 7
2.3. Text Substitution/Response Piping ............................................................................................. 7
2.4. Validation Code .......................................................................................................................... 8
2.5. Script Nodes ............................................................................................................................. 10
2.6. Dynamic Questions.................................................................................................................. 11
2.7. Script Execution when Respondent Moves Backwards ........................................................... 12
2.8. The Syntax Highlighter ............................................................................................................. 12
2.8.1. Using the Syntax Highlighter ............................................................................................ 13
2.8.2. Syntax Highlighter Limitations........................................................................................... 14
3. Comments ...................................................................................................................................... 15
4. Types, Variables and Constants ................................................................................................. 16
4.1. Naming ..................................................................................................................................... 16
4.2. Data Declaration ...................................................................................................................... 16
4.3. Undefined Values .................................................................................................................... 17
4.4. Null .......................................................................................................................................... 17
4.5. Types ....................................................................................................................................... 19
4.5.1. Numeric ............................................................................................................................ 19
4.5.1.1. Integers ...................................................................................................................... 19
4.5.1.2. Floating-point Data .................................................................................................... 20
4.5.2. Boolean ............................................................................................................................. 21
4.5.3. Characters and Strings ...................................................................................................... 21
4.5.3.1. Unicode...................................................................................................................... 22
4.6. Conversion between Types/Conversion Functions ................................................................... 22
4.6.1. Conversion Methods in JScript .NET ................................................................................ 23
4.6.1.1. parseInt ....................................................................................................................... 23
4.6.1.2. parseFloat ................................................................................................................... 23
4.6.1.3. isNaN .......................................................................................................................... 24
4.6.1.4. isFinite ........................................................................................................................ 24
4.6.1.5. toString ....................................................................................................................... 24
4.6.1.6. valueOf ....................................................................................................................... 24
4.6.2. Conversion Methods in Forsta ........................................................................................... 24
4.6.2.1. toNumber .................................................................................................................... 24
4.6.2.2. toInt ............................................................................................................................. 24

- iii -
Forsta v2022 Scripting Manual Forsta Confidential

4.6.2.3. toDecimal .................................................................................................................... 25


4.6.2.4. toBoolean.................................................................................................................... 25
4.6.2.5. toDate ........................................................................................................................ 26
4.6.2.6. day ............................................................................................................................. 26
4.6.2.7. month ......................................................................................................................... 26
4.6.2.8. year............................................................................................................................ 26
4.6.2.9. datestring ................................................................................................................... 26
5. Operators and Expressions ......................................................................................................... 27
5.1. Terminology ............................................................................................................................. 27
5.2. Arithmetic Operators ................................................................................................................ 27
5.3. Logical Operators .................................................................................................................... 28
5.4. Comparison Operators ............................................................................................................ 28
5.5. String Operators ...................................................................................................................... 29
5.6. Assignment Operators ............................................................................................................. 29
5.7. new .......................................................................................................................................... 30
5.8. The Conditional Expression Ternary Operator ......................................................................... 30
5.9. Coercion .................................................................................................................................. 32
5.10. Operator Precedence ............................................................................................................. 33
5.11. Short Circuit Evaluation ......................................................................................................... 34
6. Simple Statements........................................................................................................................ 35
6.1. Declarations .............................................................................................................................. 35
6.2. Assignment Statements ............................................................................................................ 35
6.3. The if Statement ....................................................................................................................... 35
6.3.1. if ........................................................................................................................................ 36
6.3.2. if-else ................................................................................................................................ 36
6.3.3. Using Curly Brackets in if Statements............................................................................... 36
6.4. The switch Statement ............................................................................................................... 37
7. Arrays ............................................................................................................................................ 39
7.1. Typed Arrays ........................................................................................................................... 39
7.1.1. Declaring Typed Arrays .................................................................................................... 39
7.2. JScript Arrays .......................................................................................................................... 40
7.2.1. Declaring JScript Arrays ................................................................................................... 40
7.3. length ........................................................................................................................................ 41
7.4. The length Property .................................................................................................................. 41
8. Methods of the Form Objects ...................................................................................................... 42
8.1. get and set ................................................................................................................................ 42
8.2. label .......................................................................................................................................... 42
8.3. text ............................................................................................................................................ 42
8.4. instruction ................................................................................................................................. 43
8.5. value ......................................................................................................................................... 43
8.6. valueLabel ................................................................................................................................ 43
8.7. domainValues ........................................................................................................................... 43
8.8. domainLabels ........................................................................................................................... 43
8.9. categories ................................................................................................................................. 43
8.10. categoryLabels ....................................................................................................................... 45
8.11. values ..................................................................................................................................... 45
8.12. getType.................................................................................................................................. 46

- iv -
Forsta Confidential Forsta v2022 Scripting Manual

8.13. GetAdditionalColumnValue .................................................................................................... 46


8.14. any ......................................................................................................................................... 47
8.15. all ........................................................................................................................................... 48
8.16. none....................................................................................................................................... 48
8.17. between ................................................................................................................................. 48
8.18. isNearBy ................................................................................................................................ 48
8.19. latitude and longitude............................................................................................................. 48
8.20. Applying the Methods on Different Types of Questions ......................................................... 48
8.20.1. Open Text Question........................................................................................................ 49
8.20.2. Date ................................................................................................................................ 49
8.20.3. Single Question .............................................................................................................. 50
8.20.4. Single Question with Boolean Property Set .................................................................... 51
8.20.5. Multi Question ................................................................................................................. 52
8.20.6. Open Text List ................................................................................................................ 53
8.20.7. Geolocation Question ..................................................................................................... 54
8.20.8. Grid Question.................................................................................................................. 55
8.20.9. Other Specify Items ........................................................................................................ 56
8.20.10. Referencing the Elements of a Multi, Ranking, Open Text List, Numeric List or Grid ... 57
8.20.10.1. Element of a Grid Question.................................................................................... 58
8.20.10.2. Element of a Multi Question ................................................................................... 58
8.20.10.3. Element of an Open Text List Question ................................................................. 58
8.20.11. Loops ............................................................................................................................ 58
8.20.12. 3D Grid ......................................................................................................................... 59
8.20.13. Implicit Conversion of Arrays to Strings ........................................................................ 59
8.21. Overview – Methods of Basic Variable Objects in Forsta ...................................................... 60
9. Loop Statements .......................................................................................................................... 62
9.1. The while Statement ................................................................................................................. 62
9.2. The do while Statement ............................................................................................................ 65
9.3. The for Statement ..................................................................................................................... 66
9.4. Loop Nodes ............................................................................................................................. 67
9.5. The break Statement ................................................................................................................ 67
9.6. The continue Statement ............................................................................................................ 68
9.7. The label Statement/Nested Loops........................................................................................... 69
10. Functions ..................................................................................................................................... 72
10.1. Built-in Functions ................................................................................................................... 72
10.1.1. Arithmetic Functions ....................................................................................................... 72
10.1.1.1. Sum .......................................................................................................................... 72
10.1.1.2. Count ........................................................................................................................ 75
10.1.1.3. Average .................................................................................................................... 76
10.1.1.4. Max and Min ............................................................................................................. 77
10.1.2. Range .............................................................................................................................. 77
10.1.3. Context Information ........................................................................................................ 78
10.1.3.1. GetSurveyChannel ................................................................................................... 78
10.1.3.2. IsInProductionMode ................................................................................................. 79
10.1.3.3. GetRenderingMode ................................................................................................. 79
10.1.3.4. GetContentType ...................................................................................................... 79
10.1.3.5. AdvancedWIFeaturesEnabled ................................................................................. 80
10.1.3.6. DynamicQuestionsEnabled...................................................................................... 80

-v-
Forsta v2022 Scripting Manual Forsta Confidential

10.1.3.7. IsDynamicQuestionCallback .................................................................................... 80


10.1.3.8. IsInlineSurveyCallback............................................................................................. 81
10.1.3.9. CurrentForm ............................................................................................................ 81
10.1.3.10. GetRespondentUrl ................................................................................................. 82
10.1.3.11. RedirectToRespondentUrl ..................................................................................... 84
10.1.3.12. CurrentID ............................................................................................................... 84
10.1.3.13. CurrentLang ........................................................................................................... 85
10.1.3.14. CurrentPID ............................................................................................................. 85
10.1.3.15. CurrentLoops ......................................................................................................... 85
10.1.3.16. GetRespondentValue and SetRespondentValue ................................................... 85
10.1.3.17. InterviewStart, InterviewEnd, SetInterviewStart and SetInterviewEnd ................... 86
10.1.3.18. GetStatus and SetStatus ....................................................................................... 87
10.1.3.19. Forward.................................................................................................................. 88
10.1.3.20. IsInRdgMode ......................................................................................................... 88
10.1.3.21. SetRandomCategories........................................................................................... 88
10.1.3.22. TerminateLoop....................................................................................................... 88
10.1.3.23. IsAccessibleMode and SetAccessibleMode........................................................... 89
10.1.3.24. UserParameters ..................................................................................................... 89
10.1.3.25. GetDeviceInfo ........................................................................................................ 90
10.1.3.26. GetQuestionIds ...................................................................................................... 92
10.1.3.27. Get3DGridQuestionIds........................................................................................... 92
10.1.3.28. GetSurveyPackageVersion .................................................................................... 93
10.1.3.29. GetCompanyId....................................................................................................... 93
10.1.3.30. GetSurveyName .................................................................................................... 93
10.1.3.31. GetResponseId ...................................................................................................... 93
10.1.3.32. GetLanguageCodes ............................................................................................... 93
10.1.3.33. FormExists ............................................................................................................. 94
10.1.4. Browser Information........................................................................................................ 94
10.1.4.1. BrowserType, BrowserVersion and trapBrowser ...................................................... 94
10.1.4.2. RequestIP ................................................................................................................ 95
10.1.5. Ranking Questions and Capture Order Multis ................................................................ 95
10.1.5.1. First ........................................................................................................................... 96
10.1.5.2. Nth ........................................................................................................................... 97
10.1.5.3. AnswerOrder............................................................................................................ 98
10.1.5.4. Setting Variables for Nth Mentioned / Ranked for Reporting Purposes ................... 98
10.1.6. Table Lookup Specific Functions .................................................................................... 98
10.1.6.1. GetDBColumnValue ................................................................................................ 98
10.1.7. Offline Mobile App Specific Functions - CAPI and AskMe App ..................................... 100
10.1.7.1. CAPI and AskMe App Shared Functions ............................................................... 100
10.1.7.1.1. GetDeviceUniqueId ......................................................................................... 100
10.1.7.1.2. GetOfflineInfo .................................................................................................. 100
10.1.7.1.3. GetSurveyDeviceVariable, SetSurveyDeviceVariable, GetUserDeviceVariable and
SetUserDeviceVariable ...................................................................................................... 101
10.1.7.1.4. Background Audio Capture ............................................................................. 102
10.1.7.1.5. openVideoInApp ............................................................................................. 102
10.1.7.1.6. openAudioinApp ............................................................................................. 103
10.1.7.2. CAPI App Specific Functions ................................................................................. 103
10.1.7.2.1. PostponeInterview .......................................................................................... 103

- vi -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.7.2.2. GetCapiInterviewerName................................................................................ 103


10.1.7.2.3. GetCapiDeviceOs ........................................................................................... 103
10.1.7.2.4. GetCapiBatteryLevel ....................................................................................... 104
10.1.7.3. CapiAssignRespondent ......................................................................................... 104
10.1.7.4. CapiUnassignRespondent ..................................................................................... 104
10.1.7.5. AskMe App Specific Functions .............................................................................. 104
10.1.7.5.1. GetOfflineSurveyDescription and SetOfflineSurveyDescription ...................... 104
10.1.7.5.2. Survey Reminders .......................................................................................... 105
10.1.7.5.3. GetAdvertisingInfo .......................................................................................... 108
10.1.7.5.4. notifyNativeApp ............................................................................................... 108
10.1.8. CATI Specific Functions ............................................................................................... 108
10.1.8.1. Redo ...................................................................................................................... 109
10.1.8.2. GetTelephoneNumber and SetTelephoneNumber ................................................ 109
10.1.8.3. GetExtensionNumber and SetExtensionNumber ................................................... 110
10.1.8.4. GetTimeZoneId and SetTimeZoneId ...................................................................... 112
10.1.8.5. GetExtendedStatus and SetExtendedStatus ......................................................... 113
10.1.8.6. GetLastInterviewStart ............................................................................................ 114
10.1.8.7. GetLastChannelId .................................................................................................. 114
10.1.8.8. GetCatiInterviewerId .............................................................................................. 114
10.1.8.9. GetCallAttemptCount ............................................................................................. 115
10.1.8.10. GetTotalAttempts ................................................................................................. 115
10.1.8.11. GetDialMode, SetDialMode and GetDialingMode ................................................ 115
10.1.8.12. GetDialStatus....................................................................................................... 115
10.1.8.13. GetDialType ......................................................................................................... 117
10.1.8.14. GetTotalDuration ................................................................................................. 117
10.1.8.15. GetCatiInterviewerName...................................................................................... 117
10.1.8.16. GetCatiAppointmentTime..................................................................................... 118
10.1.8.17. GetCatiRespondentUrl ......................................................................................... 119
10.1.8.18. GetCatiStationId .................................................................................................. 119
10.1.8.19. StartVoiceRecording and StopVoiceRecording ................................................... 119
10.1.8.20. fr .......................................................................................................................... 119
10.1.8.21. IsCallExpired........................................................................................................ 120
10.1.8.22. AddToCatiBlacklist ............................................................................................... 120
10.1.8.23. GetParamValue ................................................................................................... 120
10.1.8.24. StartCATIAudioPlayback ..................................................................................... 121
10.1.8.25. IsInOpenendReviewMode.................................................................................... 121
10.1.8.26. AddRespondentToCati......................................................................................... 122
10.1.8.27. CreateCatiAppointment........................................................................................ 122
10.1.8.28. CreateCustomAppointment................................................................................... 123
10.1.8.29. EnableLiveMonitoring and StartScreenRecording ............................................... 123
10.1.8.30. IsCatiGroupMember ............................................................................................ 124
10.1.8.31. IsCatiIvr................................................................................................................ 124
10.1.8.32. IsCatiInbound....................................................................................................... 124
10.1.8.33. Linked Surveys / Interviews ................................................................................. 124
10.1.8.33.1. GetCatiInterviews.......................................................................................... 124
10.1.8.33.2. SetNextCatiInterview / SetNextCatiInterviewToPrevious .............................. 125
10.1.8.33.3. GetCatiLinkedInterviews ............................................................................... 125
10.1.8.34. Writing Custom CATI Script Code ....................................................................... 125

- vii -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.8.34.1. Accessing the Call Object in Custom Scripting ............................................. 125


10.1.9. Multimode Functions - CAWI to CAPI ........................................................................... 128
10.1.9.1. CapiAssignRespondent ......................................................................................... 128
10.1.9.2. CapiUnassignRespondent ..................................................................................... 129
10.1.10. Chart ........................................................................................................................... 129
10.1.10.1. ChartTotal ............................................................................................................ 129
10.1.11. Quota .......................................................................................................................... 129
10.1.11.1. qf ........................................................................................................................... 130
10.1.11.2. qc and qt ............................................................................................................... 131
10.1.11.3. GetLeastFilledQuotaCodes.................................................................................. 131
10.1.12. Credits in Panels......................................................................................................... 134
10.1.12.1. SetPanelistCredit .................................................................................................. 134
10.1.12.2. Using Custom Variables with SetPanelistCredit .................................................. 135
10.1.12.3. GetPanelistCreditBalance ..................................................................................... 135
10.1.12.4. GetPanelistCredits ............................................................................................... 136
10.1.12.5. Using Custom Variables when Getting Panelist Credits ....................................... 137
10.1.13. Standard and Professional Panels.............................................................................. 138
10.1.13.1. CreatePanelist ...................................................................................................... 138
10.1.13.2. UpdatePanelVariables .......................................................................................... 139
10.1.13.3. GetPanelVariables ................................................................................................ 140
10.1.13.4. UpdateSurveyHistoryPanelVariables ................................................................... 141
10.1.13.5. UpdateSurveyHistoryVariables (obsolete) ............................................................ 141
10.1.13.6. IsFromCommunityPortal and GetCommunityPortalReturnUrl ............................... 141
10.1.13.7. IsFieldValueTaken ................................................................................................ 142
10.1.13.8. isEmailTaken ........................................................................................................ 142
10.1.13.9. DeleteCurrentResponse ....................................................................................... 143
10.1.13.10. Functions for Sample Only................................................................................. 143
10.1.13.11. AddPanelSurveyHistory ..................................................................................... 145
10.1.14. Basic Panels ............................................................................................................... 145
10.1.14.1. isUsernameTaken ................................................................................................. 146
10.1.15. Classification Functions .............................................................................................. 146
10.1.15.1. IsNumeric and IsInteger ........................................................................................ 146
10.1.15.2. IsDateFmt and IsDate ........................................................................................... 146
10.1.15.3. IsEmail .................................................................................................................. 149
10.1.15.4. IsNet ..................................................................................................................... 150
10.1.16. General Utilities .......................................................................................................... 150
10.1.16.1. SendMail ............................................................................................................... 150
10.1.16.2. SendMailMultipart ................................................................................................. 153
10.1.16.3. SendPdfMail ........................................................................................................ 154
10.1.16.4. SendPdfMailWithCopy ......................................................................................... 155
10.1.16.5. Redirect ............................................................................................................... 156
10.1.16.5.1. Opening a Specific Survey Page or Call Block ............................................. 157
10.1.17. Survey Router Functions ............................................................................................ 158
10.1.17.1. GetAvailableSurvey ............................................................................................. 159
10.1.17.2. RedirectToRouterSurvey ..................................................................................... 159
10.1.17.3. GetRouterName ................................................................................................... 160
10.1.18. 3rd Party Integrations ................................................................................................. 161
10.1.18.1. CintFulfillmentRespondentsTransition ................................................................. 161

- viii -
Forsta Confidential Forsta v2022 Scripting Manual

10.2. Creating Your Own Functions .............................................................................................. 161


10.2.1. Defining functions .......................................................................................................... 162
10.2.2. Function Call .................................................................................................................. 162
10.2.3. Functions with a Fixed Number of Arguments .............................................................. 162
10.2.4. Functions with a Variable Number of Arguments ........................................................... 162
10.2.5. The return Statement ..................................................................................................... 163
11. Objects ...................................................................................................................................... 164
11.1. Properties ............................................................................................................................. 164
11.2. Methods ................................................................................................................................ 164
11.3. Constructors: Creating Instances of Objects ........................................................................ 164
12. The f Function ............................................................................................................................ 165
12.1. Calling the f Function ............................................................................................................ 165
12.2. Storing the Form Object in a Variable .................................................................................. 165
12.3. Compounds .......................................................................................................................... 165
12.4. Properties ............................................................................................................................. 167
12.5. The f Function Methods ........................................................................................................ 169
13. Working with Sets...................................................................................................................... 171
13.1. Constructor ........................................................................................................................... 171
13.2. Functions Returning Sets .................................................................................................... 171
13.2.1. The a Function ............................................................................................................... 171
13.2.2. set, nset and nnset ........................................................................................................ 171
13.2.3. Iset ................................................................................................................................ 171
13.2.4. The Filter Function ......................................................................................................... 172
13.2.5. The f Function ................................................................................................................ 172
13.3. Methods of the Set Object .................................................................................................... 172
13.3.1. inc ................................................................................................................................. 172
13.3.2. size ................................................................................................................................ 173
13.3.3. union, isect and diff ........................................................................................................ 173
13.3.4. Combining Set Operators ............................................................................................. 176
13.3.5. members ....................................................................................................................... 178
13.3.6. add and remove ............................................................................................................ 179
13.3.7. .any, .all and .none ....................................................................................................... 179
13.4. User-Defined Functions in Code or Scale Masks ................................................................ 180
14. Some Useful JScript .NET Objects.......................................................................................... 181
14.1. The Date Object.................................................................................................................... 181
14.1.1. Constructors .................................................................................................................. 181
14.1.2. Date Object Methods ................................................................................................... 182
14.1.2.1. Static Methods ....................................................................................................... 182
14.1.2.1.1. parse ................................................................................................................ 182
14.1.2.1.2. UTC ................................................................................................................ 182
14.1.2.2. Methods for Setting or Retrieving Values of Parts of Dates ................................... 183
14.1.2.2.1. getFullYear, getUTCFullYear, setFullYear and setUTCFullYear .................... 183
14.1.2.2.2. getMonth, getUTCMonth, setMonth and setUTCMonth ................................... 184
14.1.2.2.3. getDay and getUTCDay ................................................................................... 184
14.1.2.2.4. getDate, getUTCDate, setDate and setUTCDate ............................................ 185
14.1.2.2.5. getHours, getUTCHours, setHours and setUTCHours..................................... 185
14.1.2.2.6. getMinutes, getUTCMinutes, setMinutes and setUTCMinutes ......................... 185

- ix -
Forsta v2022 Scripting Manual Forsta Confidential

14.1.2.2.7. getSeconds, getUTCSeconds, setSeconds and setUTCSeconds ................... 186


14.1.2.2.8. getMilliseconds, getUTCMilliseconds, setMilliseconds and setUTCMilliseconds186
14.1.2.2.9. getTime and setTime ....................................................................................... 186
14.1.2.2.10. getTimezoneOffset......................................................................................... 187
14.1.2.3. Date Conversion Methods ..................................................................................... 187
14.1.2.3.1. valueOf ........................................................................................................... 187
14.1.2.3.2. toLocaleString, toString and toUTCString ....................................................... 187
14.1.3. Date Functions and Date Questions ............................................................................. 187
14.1.3.1. InterviewStart and InterviewEnd ............................................................................. 188
14.1.3.2. IsDateFmt and IsDate ............................................................................................. 188
14.1.3.3. The Date Question Type ......................................................................................... 192
14.2. The Math Object ................................................................................................................... 193
14.2.1. Properties ..................................................................................................................... 193
14.2.2. Math Object Methods .................................................................................................... 193
14.2.2.1. Trigonometric Functions ......................................................................................... 193
14.2.2.2. Rounding ................................................................................................................ 194
14.2.2.3. Random ................................................................................................................. 195
14.2.2.4. Maximum and Minimum ......................................................................................... 197
14.2.2.5. Absolute value ........................................................................................................ 197
14.2.2.6. Exponents, Logarithms and Square Root ............................................................... 197
14.3. The String Object .................................................................................................................. 198
14.3.1. Constructors .................................................................................................................. 198
14.3.2. Properties ..................................................................................................................... 198
14.3.3. Index .............................................................................................................................. 198
14.3.4. Converting to String from Other Types ......................................................................... 198
14.3.5. Methods for String Objects ........................................................................................... 198
14.3.5.1. Methods Returning a Character or a Character Code at a Specific Index .............. 198
14.3.5.2. Building a String from a Number of Unicode Characters ........................................ 199
14.3.5.3. Changing Case ....................................................................................................... 199
14.3.5.4. Searching for a Substring within a String ............................................................... 199
14.3.5.5. Retrieving a Section of a String (Substring) ............................................................ 200
14.3.5.6. Splitting and Joining Strings................................................................................... 201
14.3.5.7. Retrieving the String Value .................................................................................... 202
14.3.5.8. Methods that Add HTML Tags to a String ............................................................... 202
14.3.5.9. Removing Leading/Trailing White Space Characters ............................................ 203
14.4. Regular Expressions............................................................................................................. 203
14.4.1. Regular Expression Syntax........................................................................................... 204
14.4.1.1. Ordinary Characters .............................................................................................. 204
14.4.1.2. Special Characters ................................................................................................ 204
14.4.1.3. Non-Printable Characters ...................................................................................... 206
14.4.1.4. Bracket Expressions ............................................................................................... 206
14.4.1.5. Quantifiers ............................................................................................................. 207
14.4.1.6. Anchors.................................................................................................................. 208
14.4.1.7. Alternation and Grouping ........................................................................................ 209
14.4.1.8. Back-References .................................................................................................... 210
14.4.1.9. Digits and Word Characters ................................................................................... 211
14.4.1.10. Hexadecimal and Octal Escape Values and Unicode Characters ........................ 211
14.4.2. Order of Precedence .................................................................................................... 212

-x-
Forsta Confidential Forsta v2022 Scripting Manual

14.4.3. The Regular Expression Object ..................................................................................... 212


14.4.3.1. Regular Expression Methods .................................................................................. 212
14.4.4. String Object Methods that Use Regular Expression Objects ....................................... 213
14.5. The Array Object.................................................................................................................. 215
14.5.1. Combining Arrays .......................................................................................................... 215
14.5.2. Converting Arrays to Strings .......................................................................................... 215
14.5.3. Removing and Adding Elements................................................................................... 216
14.5.4. Changing the Order of the Elements ............................................................................. 216
14.5.5. slice and splice ............................................................................................................. 219
15. Customizing Standard Error Messages .................................................................................. 220
15.1. Functions for Standard Validation ........................................................................................ 220
15.2. Template Based Error Messages ........................................................................................ 221
15.2.1. Answer Required Checks ............................................................................................. 222
15.2.2. Exclusivity Tests ........................................................................................................... 222
15.2.3. Other-Specify Checking ................................................................................................ 223
15.2.4. Rank Order Tests .......................................................................................................... 224
15.2.5. Answer Size For Fixed-Width Fields ............................................................................. 224
15.2.6. Numeric Validation........................................................................................................ 225
15.2.7. Precision Error Tests ..................................................................................................... 225
15.2.8. Scale Error Tests ........................................................................................................... 226
15.2.9. Range Error Tests ......................................................................................................... 226
15.2.10. Columns in 3D grid ..................................................................................................... 227
16. Useful ASP.NET Intrinsic Objects ........................................................................................... 228
16.1. Request ................................................................................................................................ 228
16.1.1. Request.Form ............................................................................................................... 228
16.1.2. RequestForm ................................................................................................................ 228
16.1.3. QueryString................................................................................................................... 228
16.1.4. Request.Cookies .......................................................................................................... 229
16.1.5. ServerVariables ............................................................................................................ 229
16.2. Response ............................................................................................................................. 231
16.2.1. Write ............................................................................................................................. 231
16.2.2. Cookies ......................................................................................................................... 232
17. Scripting in Reportal ................................................................................................................ 234
17.1. Where is Scripting Used in Reportal? .................................................................................. 234
17.2. Caching of Tables ................................................................................................................ 234
17.3. General Concepts ................................................................................................................. 235
17.3.1. Accessing Survey Content ............................................................................................ 235
17.3.2. Methods ......................................................................................................................... 235
17.3.3. Guidelines ...................................................................................................................... 235
17.3.4. Question Category ........................................................................................................ 236
17.3.5. The Role Column .......................................................................................................... 239
17.4. Script Types ......................................................................................................................... 239
17.4.1. Report Level Scripts ..................................................................................................... 239
17.4.1.1. Codelibrary Script .................................................................................................. 239
17.4.1.2. Permission Script ................................................................................................... 240
17.4.2. Page Level Scripts ........................................................................................................ 241
17.4.2.1. Page Validation Script ........................................................................................... 242
17.4.2.2. Page Hide Script .................................................................................................... 243

- xi -
Forsta v2022 Scripting Manual Forsta Confidential

17.4.3. Parameter Scripts ......................................................................................................... 244


17.4.3.1. Domain Script ........................................................................................................ 244
17.4.3.2. Mask Script ............................................................................................................ 245
17.4.3.3. Filter Summary Script ............................................................................................ 246
17.4.4. Component Scripts ....................................................................................................... 246
17.4.4.1. Render Scripts ........................................................................................................ 246
17.4.4.2. Hide Expression Script ........................................................................................... 246
17.4.4.3. Aggregated Table Script ........................................................................................ 247
17.4.4.4. Verbatim Table Script ............................................................................................ 248
17.4.4.5. Chart Script ............................................................................................................ 248
17.4.4.6. Gauge Script .......................................................................................................... 249
17.4.4.7. Hit List Script.......................................................................................................... 249
17.4.4.8. Text Script.............................................................................................................. 250
17.4.5. Filter Scripts .................................................................................................................. 250
17.5. Validation ............................................................................................................................. 251
18. Testing Survey Scripts ............................................................................................................. 252
18.1. Testing in Professional Authoring ........................................................................................ 252
18.1.1. Check Script Code ........................................................................................................ 252
18.1.2. Manual Testing ............................................................................................................. 252
18.1.3. Random Data Generator .............................................................................................. 253
18.1.4. Tips for Debugging ....................................................................................................... 254
18.1.4.1. Response.Write ..................................................................................................... 254
18.2. Testing in Survey Designer .................................................................................................. 254
19. Programming Conventions ...................................................................................................... 256
19.1. Comments ........................................................................................................................... 256
19.2. Naming Conventions ............................................................................................................ 256
19.3. Spaces and Line Breaks ...................................................................................................... 256
19.4. Curly Brackets ..................................................................................................................... 256
19.5. Semi Colon .......................................................................................................................... 257
19.6. The Step by Step Approach .................................................................................................. 257
19.7. Writing Efficient Code .......................................................................................................... 258
20. Differences between JavaScript and JScript ......................................................................... 259
20.1. Syntax and Behavior Differences......................................................................................... 259
20.2. Usercode API Function Declaration Changes ..................................................................... 260
20.2.1. Standard Code.............................................................................................................. 260
20.2.2. ExprObj ......................................................................................................................... 261
20.2.3. Set ................................................................................................................................ 261
20.2.4. Request ........................................................................................................................ 261
20.2.5. Response ..................................................................................................................... 262
20.2.6. Server ........................................................................................................................... 265
20.2.7. NameValueCollection ................................................................................................... 266
20.2.8. Browser ........................................................................................................................ 267
20.2.9. JavaScriptScriptingExtensionPoint ............................................................................... 269
20.2.10. JavaScriptCallResultCollection ................................................................................... 270
20.2.11. Cookies ....................................................................................................................... 270
20.2.12. Cookie ........................................................................................................................ 271
APPENDIX A: Answers to Exercises ............................................................................................. 272

- xii -
Forsta Confidential Forsta v2022 Scripting Manual

APPENDIX C: Forsta Language Codes .......................................................................................... 275


APPENDIX D: Codepage ................................................................................................................. 283
APPENDIX E: List of Examples ...................................................................................................... 285
APPENDIX F: QSL-to-Forsta Script Conversions ......................................................................... 288
Index ................................................................................................................................................. 296

- xiii -
Forsta v2022 Scripting Manual Forsta Confidential

What's New in this Revision?

Note: Only the latest changes to this documentation are listed here. Changes made to earlier revisions are
listed in the "Changes to the User Documentation" document which can be downloaded from the Forsta
Extranet at https://extranet.confirmit.com.

The following changes have been made since the last revision:

• The manual is updated with new logo, company and product names. Note that images will be updated at a
later date, and URLs, folder names etc. will be corrected as the changes become applicable.
• The SendPdfMail topic is updated (see SendPdfMail on page 154 for more information).
• The SendPdfMailWithCopy topic is updated (see SendPdfMailWithCopy on page 155 for more information).
• The QualityTerminate code example is added to the CintFulfillmentRespondentsTransition topic (see
CintFulfillmentRespondentsTransition on page 161 for more information).
• Appendix B is removed as it is no longer relevant.

Note: The general layout and language in this document is continually being corrected, adjusted and
improved to ensure the user has the best possible source of information. Only NEW information and details
of functionality that has changed since the previous revision are listed here - minor corrections to the text
and document layout are not listed.

Important!
We need your feedback so we can improve this document and provide you with the information you require. If
you have any comments or constructive criticism concerning the content or layout of this documentation,
please send an email to [email protected]. Please include in your email the section number and/or
heading text of the section to which your comment applies.

- xiv -
Forsta Confidential Forsta v2022 Scripting Manual

1. Introduction
Most Forsta surveys contain a quantity of script code. Scripts are used:

• In conditions, for controlling the flow through the questionnaire (skipping logic) and controlling whether or not
questions are to be displayed (question masks and column masks (in 3D grids)).
• For filtering the lists displayed in questions and the iterations in loops based on previous answers (code and
scale masks).
• In form elements for text substitution (response piping).
• For custom validation of user input.
• In general-purpose code contained in script nodes.
Forsta uses Microsoft’s JScript .NET scripting engine to evaluate all questionnaire expressions and to execute scripts.
The run-time environment of the interview engine supplies a number of functions and objects that provide references
to and let you manipulate survey variables. This documentation covers some of the fundamentals of JScript.NET and
the functions and objects provided by Forsta.
JScript.NET is not a condensed version of another programming language, nor is it a simplification of anything. It is a
modern scripting language with a wide variety of applications.
JScript .NET is JScript extended with features of class-based languages. All script code in Forsta will however be
wrapped as functions inside a class. This means that you cannot define your own classes in Forsta scripts.
This manual only covers server-side programming, i.e. scripts that are running on the server. It does not consider
client-side scripts (scripts that run on the respondent's browser – typically written in JavaScript), so for example
scripting of HTML elements is outside the scope of this documentation.

Tip:
Copying and Pasting the Script Code from a PDF document
When you copy a script from a PDF document and paste it into the relevant script field in Forsta, the markup is not
kept intact and the script code is pasted as a single line. To prevent this you can either:
• Open the CHM version of this document and copy the scripts from there, or
• Create or open a Wordpad or MS Word file, paste the copied script into the file, and then copy and paste the script
from the Wordpad or MS Word file into Forsta.

1.1. JScript .NET Fast Mode


To allow JScript.NET to execute with optimal performance, the JScript .NET in Forsta surveys will be compiled in fast
mode. Since fast mode places some restrictions on the type of code allowed, programs can be more efficient and
execute faster. However, some features are not available in fast mode.
In fast mode, the following JScript behaviors are triggered:

• All variables must be declared.


• Functions become constants.
• Intrinsic objects cannot have expanded properties.
• Intrinsic objects cannot have properties listed or changed.
• The arguments object is not available.
• Cannot assign to a read-only variable, field, or method.
• eval method cannot define identifiers in the enclosing scope.
• eval method executes scripts in a restricted security context.
Most of these changes should not affect scripts used in Forsta.

-1-
Forsta v2022 Scripting Manual Forsta Confidential

Important!
The eval method will not generate errors if used in Forsta, however it is not supported by Forsta and for
security reasons should not be used in Forsta surveys.

More details on those requirements that are most relevant when working with scripts, follow.

1.1.1. All Variables Must Be Declared.


Previous versions of JScript did not require explicit declaration of variables. Although this feature saves keystrokes for
programmers, it also makes it difficult to trace errors. For example, you could assign a value to a misspelled variable
name, which would neither generate an error nor return the desired result. Furthermore, undeclared variables have
global scope, which can cause additional confusion. So where previously you could write script code such as
codes = f("q1").categories();for(i=0;i<codes.length;i++) { <some
statements…> }
you must now declare the variables with the var keyword:
var codes = f("q1").categories();for(var i=0;i<codes.length;i++) { <some
statements…> }
This will still not explicitly declare the type of the variable: It may change type later as a result of an assignment. In
addition to this "loose typing", JScript .NET can now be a strongly typed language. JScript .NET provides more
flexibility than previous versions of JScript by allowing variables to be type annotated. This binds a variable to a
particular data type, and the variable can store only data of that type. Although type annotation is not required, using it
helps prevent errors associated with accidentally storing the wrong data in a variable and can increase program
execution speed (see Types, Variables and Constants on page 16 for more information).
In addition to this explicit type declaration, a technology called "implicit type inferencing" is introduced. Type
inferencing analyzes your use of variables in the script code and infers the type of the variable for you. This means
that you can achieve considerable improvements in speed using scripts also when you do not specify the type of your
variables, as long as your variables are not changing type.

1.1.2. Functions Become Constants


In previous versions of JScript, functions declared with the function statement were treated the same as variables that
held a Function object. In particular, any function identifier could be used as a variable to store any type of data.
In fast mode, functions become constants. Consequently, functions cannot have new values assigned to them or be
redefined. This prevents the accidental changing of the meaning of a function (either a user-defined or a Forsta
function). You will now not be allowed to define several functions with the same name in the same project, or reuse
the name of a function as a variable name. This should not cause particular problems for scripts used in Forsta
surveys, as it is just a bad programming habit to reuse function names anyhow. Disallowing this will avoid errors when
it is not clear what function definition to refer to. It will also make it impossible to make one of your own or the standard
functions in Forsta inaccessible because it has accidentally been redefined due for example to it being used as a
variable name.

1.1.3. The arguments Object is not Available


Previous versions of JScript provided an arguments object inside function definitions, which allowed functions to
accept an arbitrary number of arguments. The arguments object also provided a reference to the current function as
well as the calling function.
In fast mode, the arguments object is not available. However, JScript .NET allows function declarations to specify a
parameter array in the function parameter list. This allows the function to accept an arbitrary number of arguments,
thus replacing part of the functionality of the arguments object (see Functions with a Variable Number of Arguments
on page 162 for more information).

Note: It is not possible to directly access and reference the current function or calling function in fast mode.

1.1.4. Using a Sorting Function in the sort Method (on Array)


Arrays can be sorted with the sort method. This method takes an optional function name as parameter, a function
that defines how to sort elements if they are not to be sorted conventionally.

-2-
Forsta Confidential Forsta v2022 Scripting Manual

A script node is wrapped inside a class, so when you refer to the sort function you must use the keyword this to
refer to the current instance.
array.sort ({this.sortFunction})

-3-
Forsta v2022 Scripting Manual Forsta Confidential

2. Where is Scripting Used in Forsta?


Scripting is used in several places in Forsta. See the following sections for further details.

2.1. Conditions
In conditions you place a logical expression that is evaluated to true or false. If it is true the questions in the THEN-
branch will be presented to the respondent. If it is false, the interview skips the THEN-branch. If the condition has an
ELSE-branch the questions in the ELSE branch will be presented if the condition is false, otherwise they will be
skipped.

Screening Based on a Single Question


Assume the questionnaire has an age question (single), and you wish to screen respondents below the age of 18 from
doing the rest of the interview. The age question has the following answer list:

To screen respondents that answer "Below 18", insert a condition after the single question with the following syntax:A
f('age') == '1'
(The word "age" here is the question ID of the age question.) Building the conditional expression can be done by
using the condition builder:

-4-
Forsta Confidential Forsta v2022 Scripting Manual

The routing will look like this:

Status is set to "screened" in the properties of the stop node. The interview will end there for all respondents
answering "Below 18", but will continue for all the other respondents.

2.2. Filtering Answer Lists, Scales and Loops


It is very common to filter answer lists, scales and loops based on answers to previous questions. There are two types
of filters:

• Masks based on sets of codes, which are used in "code masks" of single, multi, ranking, open text list,
numerical list, grid, 3D grid questions and loops and "scale masks" of grids.
• "Column masks", which are used in 3D grids to filter the columns and are based on true/false expressions, just
like conditions.

2.2.1. Code Masks and Scale Masks


Code masks are used to filter answer lists of 3D grids, grids, single, multi, ranking, open text list and numeric list
questions, and to define the iterations that are to run in a loop. In the code mask field in properties of a question or a
loop you may use a JScript .NET expression that evaluates to a set of codes. The answer list (or loop member list) will
be filtered based on the set of codes in the code mask field.

-5-
Forsta v2022 Scripting Manual Forsta Confidential

Scale masks are used to filter scale lists of grid questions. Use the scale mask field in the properties of a grid question
to enter a JScript .NET expression that evaluates to a set of codes. The scale list will be filtered based on this set of
codes.

Filtering a Single Question Based on Answers to a Multi


Assume you have a questionnaire that uses a list called "Cars".

The list is used in two questions: First you have a multi question q2 which asks what cars you have tested, and then a
3D grid question g5 with a single question q3 which asks what car you did like most of the ones you tested, and a grid
question q4 which asks you to rate the driving experience of the car.

Now, in the 3D grid question g5 you want just the cars answered in q2 to show. This can be achieved with a code
mask with the following code:
f("q2")
that will return a set with the codes of the answers to q2. The answer list of the 3D grid g5 will be filtered so that only
the answers with these codes will be displayed.

When the question q3 is displayed to the respondent, it will only show the cars answered in q2.

-6-
Forsta Confidential Forsta v2022 Scripting Manual

2.2.2. Column and Question Masks


Column Masks are used for filtering columns in a 3D grid. If you want to dynamically exclude a column (a question
element in a 3D grid), use this field to create a JScript .NET expression that evaluates to true or false. The column is
then displayed if the result is true, and is not displayed if the result is false. If you leave the field empty, the column is
always displayed.
Question Masks are similar to Column Masks, but are used to filter an entire question. This can be useful when you
want a group of questions to appear on the same page but one or more of them should not always be displayed.
Before a condition a page break is automatically inserted, but for a question mask there will be no extra page break.

Excluding a Column (Question) in a 3D Grid


Let us say that in the 3D grid question from the previous example, we do not want inexperienced drivers (18-25 years)
to answer question q4 – driving experience.
In the column mask field of question q4 we use the following code:
f('q2') != '2'
to exclude the question from the 3D grid whenever the respondent is in the age group 18-25. (The symbol "!=" means
"not equal to".)

2.3. Text Substitution/Response Piping


To retrieve text or values from a question and insert it into the question wording of another question, you may use
caret (^ - also known as "hat") in front of and after a JScript .NET expression. This text substitution or response
piping can be used in all text fields (Title, Text, Instruction and Answer list/scale) but not in script nodes, conditions,
code/column masks or validation code fields.

Piping in the Response to a Single Question


After the respondent has picked a favorite car in q3, we want to ask how many times he or she has tested that car.
We want to pipe in the name of the car, and use the "hat" notation as follows:
^f("q3")^

-7-
Forsta v2022 Scripting Manual Forsta Confidential

2.4. Validation Code


Forsta provides several ways of validating survey responses. Some validation is based on the properties you define
for your question, for example the field width on an Open Text Question.
Sometimes you need other types of validation on questions, or you want to specify your own error messages different
from the error messages provided by the system. Enter your own validation code in the validation code field of the
question's properties.
A validation code follows a pattern similar to this:
if(expression) { RaiseError(); <some function(s) setting the text of
the error message(s)> }
We will get back to this later; so don't worry if you don't understand all of it now. The term's expression and function
will be explained later (see Operators and Expressions on page 27 for more information) and (see Arrays on page 39
for more information).
Expressions similar to those in conditions and column masks can also be placed in the validation code field, i.e.
expressions that are either true or false. If the expression is true, the function:
RaiseError()
is called. This function tells the interview engine that there is an error situation. This means that the interview page
should be re-displayed, this time with one or more error messages. The respondent is thus prohibited from moving to
the next page until the expression in the validation returns false.

-8-
Forsta Confidential Forsta v2022 Scripting Manual

There are several functions available to set the text of error messages:

ClearErrorMessage()
takes away the error message at the top of the page (will remove
the default error message).
SetErrorMessage(LangID, message)
defines the text of the error message at the top of the page (will
replace the default error message).
AppendErrorMessage(LangID, message)
adds text to the current page's error message.
ClearQuestionErrorMessage()
takes away the error message for the current question (will
remove the default question error message).
SetQuestionErrorMessage(LangID, message)
defines the text of the error message for the current question.
AppendQuestionErrorMessage(LangID,
message) adds message to the current question's error message.

-9-
Forsta v2022 Scripting Manual Forsta Confidential

For LangID, insert a code to specify which language the error message is for. For example, the code
LangIDs.en
instructs the interview engine to use this error message when the language is English. These language codes, known
as combidents, are listed in Appendix C.

Password Check
Let us say you need to password-protect an open survey. Then you can start the survey with a question asking for a
password that will be the same for all respondents. This can be set up as an open text question with the "Password"
property, so that *s are displayed instead of the text the respondent writes.
To check that the password is correct, you can insert code similar to that shown below in the validation code field of
the open question (in this example the question ID is password):
if(f("password") != "secret")
{ RaiseError(); SetErrorMessage(LangIDs.en,"Incorrect password. Please
enter the correct password to participate in the survey."); }

2.5. Script Nodes


Script nodes typically contain code for:

• Internal programming purposes.


• Defining functions used in code masks, conditions, text substitution, other script nodes or validation code.
• Assigning values to different variables.
• Performing actions such as sending an email, redirecting the respondent to a different URL, etc.

Setting complete status before the end of the survey


Sometimes you want the "complete" status to be set before the last question (e.g. an open text "Other comments"-
question), so that a respondent will be treated as a complete even though the last question(s) has not been answered.
This can be done using the SetStatus function (see GetStatus and SetStatus on page 87 for more information), in a
script node:
SetStatus("complete");

- 10 -
Forsta Confidential Forsta v2022 Scripting Manual

2.6. Dynamic Questions


This functionality allows you to use logic within a page, and enables parts of a page to be updated based on
responses to one or more questions on the same page. This can enable you to, for example, cause additional
questions to appear on the page once the respondent has answered the first question. The functionality is based on
the Ajax technology, and uses one (or more) questions as a trigger to activate logic in subsequent questions.

Note: Dynamic Questions only functions within page objects, and the trigger question(s) and the question(s)
to be triggered, must be on the same page in the survey.

The following questionnaire logic can be used within pages and will update based on the triggers:

• Text substitution/response piping.


• Question masking.
• Column masking.
• Code masking.
• Scale masking.
Inside the question that you want to be dependent of responses to one or more questions on the same page, you can
specify those other questions as “triggers”. This means that for every change to one of the trigger questions, the
question will be updated with questionnaire logic like for example masking being reevaluated.
Note that this is only supported within the “Page” object, so the “Triggers” tab will only be available on questions within
a page.

Note: The Dynamic Questions functionality is not supported in the CAPI/Kiosk console. Dynamic Questions is
supported in IE8+ (Windows), Firefox 10+ Google Chrome 26+ and Safari 5.1+ (Mac only). The functionality is
only available in surveys using Survey Layouts.
Unlike Advanced WI features, Dynamic Questions have no automatic alternative way of presenting the page if
Dynamic Questions is not supported. A function DynamicQuestionsEnabled (see DynamicQuestionsEnabled
on page 80 for more information) is provided to either screen or provide an alternative routing to respondents
whose browser does not support Dynamic Questions.

Displaying a Dynamic Follow-Up Question in the same Page

- 11 -
Forsta v2022 Scripting Manual Forsta Confidential

If for example you want a rating question to be followed by an open text question if a negative response has been
given, you can use the Dynamic Questions functionality to have that appear on the same page when the negative
response is given.
If you place a single question q9 asking people to respond on a 5-point scale, and you have an open text question
q10 that should be displayed when q9 is answered with “1” or “2”, you can use a question mask as shown below on
the open text question:
f("q9")=="1" || f("q9")=="2"
If you want these questions to appear on the same page, you can place them inside a “Page” object as shown below:

If you set “q9” as a trigger for q10, then q10 will be displayed automatically when a response is given on q9.
The DynamicQuestionsEnabled() function in the condition is used to ensure the page is only displayed to respondents
who are answering in a browser that supports the functionality.

2.7. Script Execution when Respondent Moves Backwards


Script code will be executed both when the respondent moves forwards and backwards through the survey (except for
validation code scripts - validation code is only executed when going forwards in the questionnaire).
This is important to bear in mind if your survey has a Back button. If for example you include a SendMail script, you
might not want an email to be triggered both when the respondent goes forwards and backwards. If your scripts are
used to set hidden variables based on certain conditions, you may also consider whether you need to remove the
values that were set when going backwards, instead of resetting them. There is a function called "Forward()" (see
Forward on page 88 for more information) which can be used for this purpose, to distinguish between actions taken
when respondents move forwards and backwards.

2.8. The Syntax Highlighter


The Syntax Highlighter functionality means that while scripting you no longer need to remember the functions, or look
up which properties belong to which classes and which parameters the various methods accept. Instead, all these are
available at the touch of a button. The highlighter automatically color-codes key words, and provides lists of selectable
options under specific conditions while scripting.
The Syntax Highlighter functionality is on by default for a survey, but you can switch it off in Survey Designer's Item
Editor menu (refer to the separate Survey Designer user guide for further details).
The following script editing areas support the highlighter capabilities:

• Script nodes in Survey Designer.


• Validation and masking of questions.
• Reportal scripting.
• Data Processing scripting.
• JavaScript editors.
To use the highlighter, start typing into the scripting area the function you wish to use. A drop-down list of all the
functions corresponding to the text string you have typed, opens.
The figure below shows the Syntax Highlighter in action:

- 12 -
Forsta Confidential Forsta v2022 Scripting Manual

Refer to the separate Survey Designer user guide for further information on the Syntax Highlighter and code
completion functionality.

2.8.1. Using the Syntax Highlighter


When writing code, you can automatically get a list displayed with classes, functions, methods or properties relevant
to the context you are in, covering both Forsta-specific and general JScript.NET constructions. To display the list:

1. Press CTRL+space to display the list.


If you have already started typing, the list will be filtered according to the typed string. After the name of a
class or variable, the list will appear automatically when you type period (.).

2. Type more characters to reduce the number of items in the list and jump directly to a member in the list. Use
the arrow buttons to move up and down in the list.
3. Press Enter to select an item.
On functions and methods, a parameters list will automatically pop up to give you information about the number,
names and types of parameters required by a function, template, or attribute. The parameter in bold indicates the next
parameter that is required as you type the function. Where there are different versions of the function with different
parameter lists, you can select which parameter list you wish to view.

- 13 -
Forsta v2022 Scripting Manual Forsta Confidential

To view parameter information:

1. After the name of a function or method, type an open parenthesis (as you normally would) to open the
Parameters list.
The declaration for the function will pop up under the insertion point. The first parameter in the list appears in
bold. To switch among functions, use the UP or DOWN arrow keys. As you type the function parameters, the
bold changes to reflect the next parameter that you need to enter.

2. Press ESC at any time to close the list.


Use Tab to indent lines of code. Lines of code within curly brackets, { and }, will automatically be indented. To indent
several lines of code in one operation, mark all the code you want to indent and press Tab. To un-indent, press
Shift+Tab.

2.8.2. Syntax Highlighter Limitations


The Syntax Highlighter has some limitations. No autocompletions are available for implicitly typed objects (objects
returned by functions etc.) so
Typing:
f()
will not result in an autocomplete suggestion.
Typing:
var d = new Date();
d.
will not result in an autocomplete suggestion.
Typing:
var myDate: Date;
myDate.
will result in an autocomplete suggestion.

- 14 -
Forsta Confidential Forsta v2022 Scripting Manual

3. Comments
Comments are text added in your scripts that are ignored when the script is run, but may be used to explain aspects
of the code. In JScript .NET you can add comments in two ways:

• // is used to mark the rest of the line as a comment:


//This is a comment on one line.

• /* are placed in front and */ after a comment that runs over several lines.
/* This is a comment on
two lines */
Multi-line comments cannot be nested, because everything after /* will be interpreted as comments, and when the
first */ appears, it will be interpreted as the end of the comment. So any text following the first */ will be treated as
JScript code:
/* This is an example of a
nested comment.
/* Here is the second comment, inside the first.
Both of these comments will terminate here ->*/
This line will be treated as JScript code and result in errors. */
It is recommended that you add a lot of comments in your scripts, to explain to yourself and to others what your script
is supposed to do and what it can be used for. However, as you may later want to comment out large parts of your
scripts, including comments, and it is not possible to nest comments, it is recommended that you always use the
single line comments, as shown below:
// This is a comment on
// two lines
This will make it easy to use /* and */ to comment out large sections of the script later without the nesting problems.

- 15 -
Forsta v2022 Scripting Manual Forsta Confidential

4. Types, Variables and Constants


If you need to calculate a value and save it for online reporting, for data exports or for use in the survey logic, you can
store it in a hidden question. A hidden question is an ordinary survey question with the hidden property set. This will
not be displayed to the respondent, but can be referenced like any other question.
If you need to store temporary values e.g. as part of a calculation in a script, use a JScript variableor constant. The
scope of a JScript variable or constant used in Forsta is limited. It can only be accessed within the script node or
validation code where it is defined. So if you need to access it later in the questionnaire, use a hidden question. A
hidden question can be accessed from anywhere in the questionnaire.

4.1. Naming
Variable and constant names in JScript .NET and question IDs in Forsta begin with an upper- or lowercase letter
(a-z, A-Z) or an underscore (_) and continue with letters (a-z, A-Z), digits (0-9) or underscore (_).
Examples of variable names:
countermakeMoreMoneycar123_tempiThinkThisIsReallyBoring

Note: Variable names are case sensitive, so makeMoreMoney and MakeMoreMoney are not the same variable.
This is a very common mistake.

Even though variable and constant names can start with uppercase letters, it is recommended to follow the convention
of always starting variable and constant names with a lowercase letter. This to easily distinguish it from for
example functions, where the convention is to start with an uppercase letter. Variable and constant names should be
made as descriptive as possible. For example instead of using names like x and y, you should try to describe what
they refer to, e.g. sumOfAllElements or code. When a variable or constant name consists of several words, each
new word is usually started with an uppercase letter.
There are some reserved words that cannot be used as question IDs in Forsta, and some that cannot be used as
variable or constant names in JScript .NET. See the Authoring or Survey Designer User Guide and a JScript .NET
reference manual. In addition, you cannot use names of functions (either the Forsta-provided functions described in
this manual, or functions you define yourself in script nodes (see Functions on page 72 for more information).

4.2. Data Declaration


A JScript program must specify the name of each variable that the program will use. In addition, the program may
specify what data type each variable will store. Both of these tasks are accomplished with the var statement.
var counter : int;
This will declare a variable counter to be of type integer (see Null on page 17 for more information). Here it is not
given an initial value, and will assume the default value for integers which is 0. You can also assign an initial value to it
like this:
var counter : int = 1;
Constants are declared in the same way, with the keyword const, but must be initialized. A constant's value cannot
be changed, whereas the value of a variable can.
const maxSelected : int = 100;
When you declare a variable or constant of a specific type, the value you assign to it must be valid for that type. You
cannot declare an integer variable and try to assign a string value like "This is a string" to it.
You can make several declarations in the same row by listing them separated by commas:
var counter : int = 1,sumOfAllAnswer : int = 0;
This will give code that is harder to read so it is recommended to separate them on several lines instead:
var counter : int = 1;var sumOfAllAnswer : int = 0;
Another reason for doing this is because it prevents you from doing errors that are hard to spot. Type annotation
applies only to the variable that immediately precedes it. In the following code, x is an Object because that is the
default type and x does not specify a type, while y is an int.

- 16 -
Forsta Confidential Forsta v2022 Scripting Manual

var x, y : int;
You do not need to use typed variables, but scripts that use untyped variables are slower and more prone to errors.
var counter;
Without a specified data type, the default type for a variable or constant is Object. Without an assigned value, the
default value of the variable is undefined.
You can give a variable an initial value without declaring its type:
var counter = 0;
Untyped constants are defined in the same way:
const maxSelected = 100;

4.3. Undefined Values


A variable that is declared without assigning a value to it, will, if the data type is declared, assume the default value for
that type. For example, the default value for a numeric type is zero, and the default for the String data type is the
empty string. However, a variable without a specified data type has an initial value of undefined and a data type of
undefined.
To determine if a variable or object property exists, you can compare it to the keyword undefined (which will work only
for a declared variable or property):
var x;if(x == undefined) { <some code> }
You can also check if its type is "undefined" (which will work even for an undeclared variable or property):
if(typeof(x) == "undefined") { <some code> }

4.4. Null
null is used as "no value" or "no object". In other words, it holds no valid number, string, Boolean, array, or object
(array and objects are complex data types we will get back to later). You can erase the contents of a variable (without
deleting the variable) by assigning it the null value. Note that the value undefined and null compare as equal
using the equality (==) operator.
In JScript, null does not compare as equal to 0 using the equality operator. This behavior is different from other
languages, such as C and C++.

Removing an Answer in a Single or Grid Question


You can use null to "remove" an answer to a question with a radio button (i.e. single or grid questions). Say you
have a page with two single questions, present1 and present2, at the end of the survey. The respondent should
answer just one of the questions, where the respondent can choose between two lists with incentives (for example
wine or CD):

- 17 -
Forsta v2022 Scripting Manual Forsta Confidential

You must set the "Not required" property on both questions. It is quite easy to write validation code to give an error
message when both questions are answered (as in the figure above), but the respondent cannot de-select the
answers since this is not possible with radio-buttons. Then you must remove the answers to the questions in the
validation code, i.e. setting them to the null value:
if(f("present1").toBoolean() && f("present2").toBoolean()) //both
questions answered
{
//Remove answers on both questions:
f("present1").set(null);
f("present2").set(null);
//Provide error message
RaiseError();
SetErrorMessage(LangIDs.en,"Please select either a bottle of wine or a
CD.");
}
toBoolean is used to check if there is an answer on a question (see toBoolean on page 25 for more information).
set is used to set the value of a question (see get and set on page 42 for more information).
This validation code will give this result when trying to move to the next page after selecting an answer on both
questions:

- 18 -
Forsta Confidential Forsta v2022 Scripting Manual

4.5. Types
A data type specifies the type of value that a variable, constant, or function can accept. Type annotation of variables,
constants, and functions helps reduce programming errors by making sure data that is assigned has the right types.
Furthermore, type annotation also produces faster, more efficient code.
There are several primitive types of values in JScript .NET. In the following chapters we will present these types. We
have grouped them as numeric, Boolean and string values.
Primitive types are types that can be assigned a single literal value. We will be looking at more complex types later.

4.5.1. Numeric
There are two main types of numeric data in JScript:

• Integers.
• Floating-point data.

4.5.1.1. Integers
Positive whole numbers, negative whole numbers, and the number zero are integers. They can be represented in
base 10 (decimal), base 8 (octal), and base 16 (hexadecimal). Most numbers in JScript are written in decimal. Octal
and hexadecimal rarely have any practical purpose in scripting; however, you should be aware of their denotation –
particularly for octals, since it may cause unexpected results when a number is interpreted as an octal when it was
supposed to be decimal.
You denote octal integers by prefixing them with a leading 0 (zero). They can only contain digits 0 through 7. Any
number with a leading 0 will be interpreted as an octal, as long as it is not containing the digits 8 and/or 9, in which
case it is interpreted as a decimal number.

- 19 -
Forsta v2022 Scripting Manual Forsta Confidential

You denote hexadecimal (hex) integers by prefixing them with a leading "0x" (zero and x or X). They can contain digits
0 through 9, and letters A through F (either uppercase or lowercase) only.
Both octal and hexadecimal numbers can be negative, but they cannot have a decimal portion and cannot be written
in scientific (exponential) notation.
JScript .NET supports the following integral data types: byte, ushort, uint, ulong, sbyte, short, int,
long. Variables of any integral data type can represent only a finite range of numbers. If you attempt to assign a
numeric literal that is too large or too small to an integral data type, a type-mismatch error will be generated at compile
time.

JScript value type Range

byte (unsigned) 0 to 255

ushort (unsigned short integer) 0 to 65,535

uint (unsigned integer) 0 to 4,294,967,295

ulong (unsigned extended integer) 0 to approximately 1020

sbyte (signed) -128 to 127

short(signed short integer) -32,768 to 32,767

int (signed integer) -2,147,483,648 to 2,147,483,647

long (signed extended integer) Approximately -1019 to 1019

4.5.1.2. Floating-point Data


Floating-point values are whole numbers with a decimal portion. They can either be represented with digits followed
by a decimal point. (“period”/”dot”) and more digits (e.g. 1.29384), or they can be expressed in scientific notation;
that is, an uppercase or lowercase letter e is used to represent "times ten to the power of" (e.g. 7.64e3). A number
that begins with a single 0 and contains a decimal point is interpreted as a decimal floating-point literal and not an
octal literal (see Integers on page 19 for more information).
Additionally, floating-point numbers in JScript can represent special numerical values that integral data types cannot.
These are:

• NaN(not a number). This is used when a mathematical operation is performed on inappropriate data, such as
strings or the undefined value.
• Infinity. This is used when a positive number is too large to represent in JScript.
• -Infinity (negative Infinity). This is used when the magnitude of a negative number is too large to
represent in JScript.
• Positive and Negative 0. JScript differentiates between positive and negative zero.
JScript supports the following floating-point data types:

JScript value type Range

- 20 -
Forsta Confidential Forsta v2022 Scripting Manual

float(single-precision floating- The float type can represent numbers as large as 1038 (positive
point) or negative) with an accuracy of about seven digits, and as small as
10-44. The float type can also represent NaN (Not a Number),
positive and negative infinity, and positive and negative zero.
This type is useful for large numbers where you do not need
precise accuracy. If you require very accurate numbers, consider
using the Decimal data type.

Number, double (double- The Number or double type can represent numbers as large as
precision floating-point) 10308 (positive or negative) with an accuracy of about 15 digits, and
as small as 10-323. The Number type can also represent NaN (Not a
Number), positive and negative infinity, and positive and negative
zero.
This type is useful when you need large numbers but do not need
precise accuracy. If you require very accurate numbers, consider
using the Decimal data type.

decimal The decimal type can accurately represent very large or very
precise decimal numbers. Numbers as large as 1028 (positive or
negative) and with as many as 28 significant digits can be stored as
a decimal type without loss of precision. This type is useful when
rounding errors must be avoided.
The decimal data type cannot represent NaN, positive Infinity, or
negative Infinity.

4.5.2. Boolean
The Boolean data type can only have two values. They are the literals
true
and
false
representing logical values. They are used in conditions. The THEN branch is executed when the expression
evaluates to the Boolean value true, the ELSE branch when the expression evaluates to the Boolean value false.
JScript .NET automatically converts true and false into 1 and 0 when they are used in numerical expressions. When
numbers are used in Boolean expressions, 0 is interpreted as false and any other number as true.

4.5.3. Characters and Strings


The char data type can store a single character.
A string value is a chain of zero or more characters (letters, digits, and punctuation marks) strung together. You use
the string data type to represent text in JScript.
String and char values are enclosed in single (') or double (") quotation marks. You may use any of these marks, but
always close with the same type of quotation mark as you opened it with. This is very convenient for example in
strings such as:
"I can't stand this anymore"'"This is too much for me", he said.'

Note: When you write JScript .NET code, you can have as many line breaks and blanks as you like in your
code, but never have a line break inside a string. If you have a line break inside a string, you will get an error
message.

However, there are codes you can insert for special formatting characters. E.g. for a line break use \n:

- 21 -
Forsta v2022 Scripting Manual Forsta Confidential

"I need a line break here\n and want to continue on the next line"
For apostrophe, use \':
'I can\'t stand this anymore'
Below is a table describing the special formatting characters:

Character Meaning

\' Single quote

\" Double quote

\\ Backslash

\n New line

\r Carriage return

\t Horizontal tab

\b Backspace

A string that contains zero characters ("") is an empty (zero-length) string.


There is a significant difference between the string "123" and the number 123. The number 2 will be a smaller value
than the number 123. But the string "2" is larger than the string "123", because the first character in the string is
compared first, and the character 2 is larger than the character 1 (the same system as is used in alphabetical listings
such as dictionaries and telephone directories). All values are stored as strings in the survey questions, so you must
convert them to numbers if you want them to be evaluated as numbers. See the next section in this Scripting guide.

4.5.3.1. Unicode
Jscript.NET supports Unicode characters in strings. They can be used like any other characters, but note that the
encoding of the survey pages will be set according to the settings for the active language, so that for example for
English, which by default will be set to have encoding “Western European (ISO)”, Unicode characters will not be
displayed correctly on the survey page. Only Unicode languages will display Unicode characters correctly. You should
also ensure you set the right codepage (Unicode - 65001) if using Unicode characters in SendMail and
SendMailMultiPart scripts.

4.6. Conversion between Types/Conversion Functions


Type conversion is the process of changing a value from one type to another. For example, you can convert the
string, "1234" to the number 1234. Data of any type can be converted to the String type. Some type conversions will
never succeed because the types are too different.
Some types of conversions, such as from a string to a number, are time-consuming. The fewer conversions your
program uses, the more efficient it will be.
In JScript .NET you can either have implicit or explicit conversion.
Explicit conversion is done by using the data type identifier (see Types on page 19 for more information). To explicitly
convert an expression to a particular data type, use the data type identifier followed by the expression to convert in
parentheses. Explicit conversions require more typing than implicit conversions, but you can be more certain of the
result.

- 22 -
Forsta Confidential Forsta v2022 Scripting Manual

Here is a small example showing first how the number 1234 (integer) can be converted to the string “1234” and then
to a double.
var i : int = 1234; var d : double;
var s : String; s = String(i);
Now the variable s holds the string “1234”. This type of conversion is called widening, since all possible integer
values can be converted to string and string can also hold other values. Let us continue the example:
d = double(s);
Now the variable d holds the double 1234. This type of conversion is called narrowing since there are a lot of possible
string values that cannot be converted to double (for example the string “Forsta”). Explicit narrowing conversions will
usually work, but with loss of information. The string “Forsta” converted to a double will give NaN (not a number). But
some types are incompatible and will throw an error, and for some values there is not sensible value to convert to.
Implicit conversion occurs automatically when values are assigned to variable of a certain type. The data type of the
variable determines the target data type of the expression conversion.
Here is a similar example to the one above showing first how the number 1234 (integer) can be converted to the string
“1234” and then to a double.
var i : int = 1234;
var d : double;
var s : String;s = i;
Now the variable s holds the string “1234”. It was converted to string since the receiving variable where of type string.
This is an example of widening implicit conversion. Let us continue the example:
d = s;
Now the variable d holds the double 1234. This is an example of a narrowing conversion.
When this code is compiled, compile-time warnings may state that the narrowing conversions may fail or are slow.
Implicit narrowing conversions may not work if the conversion requires a loss of information.

4.6.1. Conversion Methods in JScript .NET


4.6.1.1. parseInt
parseInt is used to convert a string value into an integer. It returns the first integer contained in the string or NaN (Not
a Number) if the string does not begin with an integer. It is a method of the Global Object. The Global Object has no
syntax, so its methods can be called directly. The expression
parseInt(string{,radix})
parses the string as an integer of base radix. radix is optional and is a value between 2 and 36 indicating the base of
the number contained in string. If not supplied, strings with a prefix of '0x' are considered hexadecimal and strings with
a prefix of '0' are considered octal. All other strings are considered decimal... Usually you want numbers to be treated
as decimals, and since a leading zero would indicate that the number is an octal number (see Numeric on page 19 for
more information), it is a good idea to always include the base 10 when using parseInt.
The function will read numbers from the beginning of the string and will stop when the first non-digit is reached:
parseInt("123xyz",10)
returns 123
parseInt("xyz123",10)
returns NaN (not a number) since the first character is not a number.

4.6.1.2. parseFloat
parseFloat returns a floating-point number converted from a string. It is a method of the Global Object. The Global
Object has no syntax, so its methods can be called directly:
parseFloat(numString)

- 23 -
Forsta v2022 Scripting Manual Forsta Confidential

The required numString argument is a string that contains a floating-point number. The function will read numbers
from the beginning of the string and will stop at the first character that cannot be interpreted as part of a floating-point
number. If the string does not begin with a floating-point number, NaN will be returned.
parseFloat("2.1e4xyz")
returns 21000 (2.1 * 104).

4.6.1.3. isNaN
The isNaN method returns true if the value is NaN, and false otherwise. It is a method of the Global Object. The
Global Object has no syntax, so its methods can be called directly: You typically use this function to test return values
from the parseInt and parseFloat methods.
isNaN(num)
num is a numeric value to test.

4.6.1.4. isFinite
The isFinite method returns true if the value is any other value than NaN, negative infinity or positive infinity. If it
is any of those three, it returns false. It is a method of the Global Object. The Global Object has no syntax, so its
methods can be called directly:
isFinite(num)
num is a numeric value to test.

4.6.1.5. toString
toString is a method of the Object object, which means it is available in any other JScript .NET object. It is used to
convert a variable into a string. Sometimes this must be done to a variable before inserting it in a question with the
set method (see get and set on page 42 for more information).

4.6.1.6. valueOf
valueOf is a method of the Object object, which means it is available in any other JScript .NET object. It returns the
primitive value of the specified object, i.e. the numeric value of a number, the string value of a string etc.

4.6.2. Conversion Methods in Forsta


There are also some methods available in Forsta to convert values.

4.6.2.1. toNumber
toNumber is a method you can use to convert the value of a question from a string into a Number (double) (see
Floating-point Data on page 20 for more information):
f(qID).toNumber()
qID is the question ID.

Note: The toNumber method requires that the question is answered, and that the value stored for the
question can be converted to a number. If not, it will return NaN (not a number).

4.6.2.2. toInt
toInt is a method you can use to convert the value of a question from a string into an integer (see Integers on page
19 for more information):
f(qID).toInt()
qID is the question ID.

- 24 -
Forsta Confidential Forsta v2022 Scripting Manual

Note: The toInt method requires that the question is answered, and that the value stored for the question can
be converted to an integer. If not, it will fail, terminate the interview with an “Internal server error” and send
an error report to the “Email address to receive emails triggered by scripting errors in interview”. The method
should either only be used when you know that there will always be a valid response to the question, or you
should check that the response is numeric before using toInt (for example using IsInteger).

4.6.2.3. toDecimal
toDecimal is a method you can use to convert the value of a question from a string into a decimal (see Floating-
point Data on page 20 for more information):
f(qID).toDecimal()
qID is the question ID.

Note: The toDecimal method requires that the question is answered, and that the value stored for the
question can be converted to a Decimal. If not, it will fail, terminate the interview with an “Internal server
error” and send an error report to the “Email address to receive emails triggered by scripting errors in
interview”. The method should either only be used when you know that there will always be a valid response
to the question, or you should check that the response is numeric before using toDecimal (for example using
IsNumeric).

Screening on a Numeric Question


Let us say you have a survey with an initial numeric question age. In this question you ask for the respondent's age.
For this survey you have defined a target: Persons between 18 and 35. To make a condition for your screening, you
have to use toNumber to convert the answer from a string into a number. You may then make an expression like this
in the condition:
f("age").toNumber() < 18 || f("age").toNumber() > 35

Note: Always use toNumber, toInt or toDecimal when you use expressions involving the operators <, <=,
>= or >, or when doing arithmetic operations on the answers.

4.6.2.4. toBoolean
toBoolean is a method that converts the variable into a Boolean (true/false). It can be used to check if a question
has been answered, or for a single question with the Boolean property, if it has been answered with the true or false
answer alternative.

Note: The Boolean question property mentioned in the last sentence above is only available in surveys using
the Optimized Database format.

f(qID).toBoolean()
If the respondent has answered the question with question ID qID, the expression will yield true, if not, false. Or, if
qID is a Boolean question, the expression will yield true if the respondent has chosen the answer corresponding to
true (1), and false if the respondent has chosen the answer corresponding to false (0)
You have already seen toBoolean used in the Removing an Answer in a Single or Grid Question example.

- 25 -
Forsta v2022 Scripting Manual Forsta Confidential

4.6.2.5. toDate
toDate can be used on date questions to return a .NET structure representing the selected date value. Note that this is
not the same as a JScript Date object. JScript supports the use of .NET structures, but not the declaration of new
ones, so sometimes it may be easier to create a JScript Date object instead for scripting purposes. See The Date
Object (chapter 14.1).
f(qID).toDate()
returns a strongly-typed Nullable DateTime object representing the date answered.

4.6.2.6. day
day can be used on date questions to get the day part of the specified date.
f(qID).day()
returns the integer value (1 - 31) representing the "day" part of the specified date. 0 is returned if no date is specified.

4.6.2.7. month
month can be used on date questions to get the month part of the specified date.
f(qID).month()
returns the integer value representing month part of the date specified, 0 if no date is specified. Conventional
numbering of months is used (1 = January, 2 = February etc.).

4.6.2.8. year
year can be used on date questions to get the year part of the specified date.
f(qID).year()
returns the integer value representing year part of the date specified, 0 if no date is specified.

4.6.2.9. datestring
datestring can be used on date questions to get a textual representation of the specified date.
f(qID).datestring()
returns the textual representation of the chosen date in accordance to the current language setting (for example,
English gives "Friday, April 25, 2010"). The same result will be achieved (a textual representation of the date in
accordance with the current language setting) when performing response piping on a date question.

Note: The date question type is only available in surveys using the "Optimized database format".

- 26 -
Forsta Confidential Forsta v2022 Scripting Manual

5. Operators and Expressions


5.1. Terminology
An operator is used to transform one or more values into a single resultant value. The values to which the operator
applies are referred to as operands. The combination of an operator and its operands is referred to as an
expression.
For example, in the expression
2 + 3
the operator + is used to transform the operands 2 and 3 into the resultant value 5.
Some operators result in a value being assigned to a variable, e.g. the assignment operator = in
x = 0;
Others produce a value that may be used in other expressions, like
2 + 3
For some operators the order of the operands does not matter:
2*3
is 6, the same is
3*2
Other operators give different results for different orderings:
3-2
is 1.
2-3
is -1.
Some operators are used only with one operand. They are called unary as opposed to binary operators, which have
two operands. Examples of unary operands: ! (logical not) and – (unary negation, as in –4 (negative numbers)).
You can combine several operators and operands to make complex expressions. To evaluate complex expressions,
you must use rules of order of precedence to know which expressions to evaluate first.
In the following we will go through the most common JScript .NET operators. Some operators that are seldom used in
Forsta scripts are left out. For a full overview, refer to a JScript .NET language reference manual.

5.2. Arithmetic Operators

Operator Description

+ Addition

- Subtraction or unary negation

* Multiplication

/ Division

% Modulus (the remainder of dividing two integers).

++ Increment and then return value (or return value and then increment)

- 27 -
Forsta v2022 Scripting Manual Forsta Confidential

-- Decrement and then return value (or return value and then decrement)

Some of these may need some explanation:


Modulus gives the remainder of dividing two integers. Examples:
7%2
gives 1 because 7/2 = 3 with a remainder of 1.
6%2
gives 0 because 6/3=2 with no remainder.
++ and --:
x++ and ++x both result in 1 being added to the value of x. x-- and --x both results in 1 being subtracted from x. They
differ in what value is returned - the value before or after the increment/decrement. ++x and --x return the value after
the increment/decrement. x++ and x-- return the value before the increment/decrement.
The distinction between x++ and ++x is illustrated in these two coding examples:

x = 3 x = 3
y = ++x y = x++
Result: x = 4 and y = 4 Result: x = 4 and y = 3

In the first example, x is increased by 1 before the value is returned and stored in y. In the second the value of x is
returned and stored in y first, and then x is increased by 1. We recommend that you be very careful when using these
operators.

5.3. Logical Operators

Operator Description

&& logical and

|| logical or

! logical not

5.4. Comparison Operators

Operator Description

== Equal

=== Strictly equal (without type conversion)

!= Not equal

- 28 -
Forsta Confidential Forsta v2022 Scripting Manual

!== Strictly not equal (without type conversion)

< Less than

<= Less than or equal

> Greater than

>= Greater than or equal

Expressions with comparison operators evaluate to true or false.


The difference between equal and strictly equal (==/===): When using == JScript .NET automatically does a type
conversion according to the types' order of precedence. For example, in the expression x == y, where x is the string '1'
and y is the number 1, the value of y will be converted to the string '1' and the expression will return true. However, in
the expression x === y (x strictly equal to y) this conversion will not be done, hence the expression will return false,
because the operands have different types.
The same applies to not equal/strictly not equal (!=/!==).

5.5. String Operators

Operator Description

+ String concatenation

Strings can be joined with the string concatenation operator +:


"For"+"sta"
will return
"Forsta"

5.6. Assignment Operators

Operator Description

Sets the variable on the left of the = operator to the value of the expression on its
=
right.

Increments the variable on the left of the += operator by the value of the expression
+= on its right. When used with strings, the value to the right of the += operator is
appended to the value of the variable on the left of the += operator.

Decrements the variable on the left of the -= operator by the value of the expression
-=
on its right.

- 29 -
Forsta v2022 Scripting Manual Forsta Confidential

Multiplies the variable on the left of the *= operator by the value of the expression on
*=
its right.

Divides the variable on the left of the /= operator by the value of the expression on its
/=
right.

Takes the modulus of the variable on the left of the %= operator using the value of the
%=
expression on its right.

The following table explains the operators +=, -=, *=, /= and %=.

Operator Equivalent to

x += y x = x+y

x -= y x = x-y

x *= y x = x*y

x /= y x = x/y

x %= y x = x%y

+= can be used for text concatenation as well as arithmetic addition:


x = "Confirm";
x += "it";
will result in x being equal to "Confirmit".

5.7. new
new is used to create new objects. Its use is described in Arrays, Objects, Working with Sets and Predefined JScript
.NET Objects.

5.8. The Conditional Expression Ternary Operator


This operator takes three operands (that is why it is called ternary):
condition ? value1 : value2
The first item is a condition that evaluates to either true or false. If the condition evaluates to true, value1 is returned. If
the condition evaluates to false, value2 is returned.

Response Piping from a Single Question with Other Specify


If you have text substitution in Forsta and want to pipe in the response to a single question with an item with the
"Other" property set, you probably want to pipe in the response in the "Other" text box instead of the answer text
(which might be something like "Other, please specify:").
Say you want to pipe in the response to the single question musical where there is one item in the answer list with
code 98 that has the "Other" property set.

- 30 -
Forsta Confidential Forsta v2022 Scripting Manual

In the text field of the question or info where you want to pipe in the response to the musical question, you can use
this code:
^f("musical").get() == "98" ? f("musical_98_other") : f("musical")^
f("musical").get() will return the code of the answer to musical (see get and set on page 42 for more
information). If this is equal to 98, the answer from the "Other" text box should be piped in
(f("musical_98_other")). If not, use normal text substitution with f("musical") so that the answer text will be
piped in.

Replacing "NO RESPONSE" in Response Piping


When there is no answer to a question, text substitution will give the text "NO RESPONSE" (different texts in other
languages than English). So if the respondent for example does not answer on a not required single question income,
response piping with
Income: ^f("income")^
will give this result:

If you instead want an empty string (i.e. no text at all) to appear when the question is not answered, use this
expression in the question where you want to pipe in the answer:

- 31 -
Forsta v2022 Scripting Manual Forsta Confidential

Income: ^f("income").toBoolean() ? f("income") : ""^


If there is an answer to income, f("income").toBoolean() will return true and f("income") will be used for text
substitution. If there is no answer, an empty string will be returned.

Note: Expressions inside ^ (carets) in question text fields, title fields and answer/scale lists in Forsta must
always return strings. You cannot run JScript .NET statements inside ^'s, however you can call a function
that returns a string.

Conditional Code Masking


It is also possible to use this operator in a code mask so a different code mask can be used dependent on a condition.
For example, if you want males (code 1) to be given different answer alternatives than women (code 2), you can base
the code mask on the "gender" question like this:
f("gender")=="1" ? nset(5) : set('1','2','4')
If the condition is evaluated as true (=male) then a code mask of 1-5 would be used; if the condition is evaluated as
false (=female) then a code mask of 1, 2 and 4 would be used.

5.9. Coercion
You can set up JScript expressions that involve values of different types without the compiler raising an exception.
Instead, one of the types will automatically be changed (coerced) to that of the other before performing the operation.
The compiler will allow all coercions unless it can prove that the coercion will always fail. Any coercion that may fail
generates a warning at compile time, and many produce a runtime error if the coercion fails.
For example, if you add a string “Forsta“ and the number 8.5, the number will be converted to a string so that the
expression
"Forsta"+8.5
will give the string "Confirmit8.5", the concatenation of the strings "Forsta" and "8.5".
In JScript :NET you can also force what type a value should be coerced to by using the target type name (see Types
on page 19 for more information).
The table below shows what the result will be when using the operator + between values of different types. It
illustrates what the order of precedence within the types. If a string is involved, the other types are converted to string.
For numbers it will give the number as a string, the Boolean value false will give the string "false" and true the
string "true". null will be converted to the string "null". An int is converted to a float in an expression with a float
value. Boolean true will be converted 1 and false to 0 when used in an expression with a numeric value. null will
be converted to 0 when used in an expression with a numeric value.

- 32 -
Forsta Confidential Forsta v2022 Scripting Manual

row + string int 123 float .123 logical logical null


column "12.34" true false

string test12.34 test123 test0.123 testtrue testfalse testnull


"test"

int 123 12312.34 246 123.123 124 123 123

float .123 0.12312.3 123.123 0.246 1.123 0.123 0.123


4

logical true12.34 124 1.123 2 1 1


true

logical false12.34 123 0.123 1 0 0


false

null null12.34 123 0.123 1 0 0

As all values returned from questions in Forsta are strings, and strings have precedence over all other types, you may
have to use some sort of conversion function to change the type before using the value from a question in your
scripts.
Exercise 1:
Find the result of this expression.
(As will be shown in the next chapter, expressions within brackets will be calculated separately before the resultant
value is concatenated with the other strings, so e.g. 192+15=207 is the resultant value from the first part that is
brought into the string.)
(192+15)+" is not the same as "+(true+206)+", but this isn't really
"+true
See the answer in APPENDIX A Answers to Exercises.

5.10. Operator Precedence


The precedence of the operators determines which operators are evaluated before others in complex expressions
where several operators are involved.
For operators on the same level of precedence, JScript .NET reads and evaluates expressions from left to right. The
table below lists the order of precedence for the operators in JScript .NET, from highest to lowest.

Operator

1 ()

2 !, -- , ++, -, new

3 *, /, %

4 +, -

5 <, <=, >, >=

- 33 -
Forsta v2022 Scripting Manual Forsta Confidential

6 ==, !=, ===, !==

7 &&

8 ||

9 ?:

10 =, +=, -=, *=, /=, %=

The minus (-) in 2 is the unary negation operator, not subtraction.


Note that parentheses are at the top of the table, so by using parentheses you can always control in what order the
expressions are calculated. It is highly recommended to use parentheses, also because it makes the expressions
easier to understand.
Here is an example showing how the order of precedence decides how an expression is calculated:
3 + 4 * 2
|
3 + 8
|
11
Exercise 2:
This is a piece of code from a script. For each one of these assignments, find the value of x, y and z after the line has
been executed:
x = 4; y=0; z=0;
y = 5*2+1-(x++ == 4 ? 2 : 8) //ex. a
z = ((x+4)%3)*900+8 //ex. b
y+= --x*8-(z>3 ? z : ++z) //ex. c
x = (z == 8 && (z % 3 == 0) || ++y < 6*5) ? --z : ++y //ex. d
See the answers in APPENDIX A Answers to Exercises.

5.11. Short Circuit Evaluation


In expressions involving the logical operators and (&&) and or (||), code will execute faster if you use a feature called
short circuit evaluation. When JScript evaluates a logical expression, it only evaluates as many sub-expressions as
required to get a result.
The logical and (&&) operator evaluates the left expression passed to it first. If that expression converts to false,
then the result of the logical and operator cannot be true regardless of the value of the right expression. Therefore,
the right expression is not evaluated.
Similarly, the logical or operator (||) evaluates the left expression first and if it converts to true, the right expression
is not evaluated.
So to make a script run most efficiently, place the conditions most likely to be true first for the logical or operator. For
the logical and operator, place the conditions most likely to be false first.
This is particularly helpful in expressions involving function calls.

- 34 -
Forsta Confidential Forsta v2022 Scripting Manual

6. Simple Statements
A statement is an instruction that makes a program perform some action.
Statements are separated either with a line break or a semicolon (;)
More than one statement may occur on a single line of text, provided that they are separated by semicolons.
A semicolon is not needed between statements that occur on separate lines, however it is recommended to use it
anyway in case the line breaks are removed later.
A statement may be written over multiple lines of text. However, do not use line break inside string constants as this
will give a script error. If you need a line break inside a string, you must use \n (see Characters and Strings on page
21 for more information). Also, postfix increment and decrement operators must appear on the same line as their
argument (e.g. i++ and i--, (see Arithmetic Operators on page 27 for more information), continue and break
keywords must appear on the same line as their label (see The break Statement on page 67 for more information),
and return must appear on the same line as its expression (see The return Statement on page 163 for more
information).
A group of JScript statements surrounded by curly brackets ({}) is called a block. Statements within a block can
generally be treated as a single statement. They are used to group a set of statements inside branches of a condition,
or inside loops and functions.

6.1. Declarations
We have used this to declare JScript .NET variables and constants.
var variableName {: type} {= expression};
or
const constantName {: type} = expression;
as for example in
var x : int = 12;
which both identifies the variable x and causes it to be implicitly declared as a variable of type int and initialized to the
value 12.
Variables and constants may or may not be bound to a specific data type.
var x = 12;
Variables may not be initialized to any value. Constants have to be initialized.
var x;

6.2. Assignment Statements


variableName assignmentOperator expression;
The assignment statement updates the value of a variable based upon an assignment operator and an expression
(and for +=, -=, *=, /= and %= also the current value of the variable). For example
var x : int = 12;
var y : int;
y = x – 2;
assigns the value 10 to y (if x is 12 as in the previous example).

6.3. The if Statement


You can use an if statement to control the flow of your code based on a logical expression. If the expression gives
the Boolean value true, the statements are executed, whereas if the expression gives the Boolean value false they are
skipped. If you use an else branch, the statements inside the else branch are executed if the expression gives the
value false.

- 35 -
Forsta v2022 Scripting Manual Forsta Confidential

6.3.1. if
if( condition )
{
statements }
If the expression inside the parenthesis is true, the statements inside the curly brackets, { and }, are executed. If the
condition is false, then the statements are skipped and execution continues on the next program line.
Note that the parentheses around the condition are required.
If-then conditions are often used when creating scripts in Forsta, especially for validation code.
We have used if conditions several times already. See the examples in Validation Code, Null and toBoolean for more
information.

6.3.2. if-else
if( condition )
{
statements }
else
{
statements }
If the condition inside the parenthesis is true, then the first set of statements is executed. If the condition is false,
then the second set of statements is executed.
Exercise 3:
What values will x and y have after running these two code samples (separately):
//Code sample 1
if(x<y)
{
x++;
}
else
{
y++;
}

//Code sample 2
if(x<y)
{
x++;
}
y++;

…when x and y are declared as


var x : int = 4;var y : int = 5;
…when x and y are declared as
var x : int = 5;var y : int = 4;
See the answers in APPENDIX A Answers to Exercises.

6.3.3. Using Curly Brackets in if Statements


Curly brackets are used to group a set of statements. If you have just one statement that should be executed inside
an if statement, you may omit the curly brackets {}. The following is equivalent to sample 1 above:

- 36 -
Forsta Confidential Forsta v2022 Scripting Manual

if(x<y)
x++;
else
y++;
However, it is easy to make mistakes when you do not use the brackets.
if(x<y)
x++;
y++;
is equivalent to sample 2 in the previous exercise, but that might be hard to spot. So it is recommended to always use
the curly brackets, both for clarity and also to simplify later modifications such as adding another statement within a
branch in the if statement.

6.4. The switch Statement


The switch statement is used when you want different statements to run for different values of a variable. Instead of
writing a lot of if statements with conditions for each of the values you want to check, you can use switch. The syntax
for the switch statement is like this:
switch (expression)
{
case value1:
statements1
break
.
.
.
case valuen:
statementsn
break
default:
statementsx
}
You may have more than one statement between each case and break, and do not need to have curly brackets in
front and after them, since for each case all the following statements will be executed until the break statement.
switch evaluates the expression and looks at the values one by one until a match is found in one of the case
statements. When a match is found, the accompanying statements are executed until a break statement is
encountered or the switch statement ends. If you omit the break statement before the next case, the following
statements will also be executed until a break is reached or you get to the end of the switch statement.
Use the default clause to provide a statement to be executed if none of the values matches the expression.
If no value matches the value of expression, and a default case is not supplied, no statements are executed.
The switch statement above will be equivalent to this code:
if(expression == value1)
{ statements1 }
...else if(expression == valuen)
{
statementsn
}
else
{
statementsx
}

Using switch to set Values for each of the Answer Alternatives on a Single

- 37 -
Forsta v2022 Scripting Manual Forsta Confidential

Let us say we have a single question where the respondent picks from a list of different concepts. Each of these has a
price, and we want to set the price in a hidden numeric question based on which of the concepts the respondent has
picked. The value in the hidden numeric question may e.g. be used in calculations later in the questionnaire. The
single question has question ID "concept" and the numeric question has question ID "price".
Here are two different ways of scripting this; the first using if and the second using switch. As you see, switch gives
more compact code that is easier to read:
//using if:
if(f("concept")=="1")
{
f("price").set(234);
}
else if(f("concept") == "2")
{
f("price").set(249);
}
else if(f("concept") == "3")
{
f("price").set(244);
}
else if(f("concept") == "4")
{
f("price").set(229);
}else
{
f("price").set(271);
}

//using switch:
switch(f("concept").get())
{
case "1":
f("price").set(234);
break
case "2":
f("price").set(249);
break
case "3":
f("price").set(244);
break
case "4":
f("price").set(229);
break
default:
f("price").set(271);
}

- 38 -
Forsta Confidential Forsta v2022 Scripting Manual

7. Arrays
Arrays are a special type of JavaScript object. An object is referred to as a complex data type because it is built from
primitive types (see The Array Object on page 215 for more information).
Arrays are objects that are capable of storing a sequence of values in one variable. A single index number (for a one-
dimensional array) or several index numbers (for an array of arrays, or a multidimensional array) references the data
in the array. You can refer to an individual element of an array with the array identifier followed with the array index in
square brackets ([]). The indexes are numbered from 0 to 1 less than the number of elements in the array. To refer to
the array as a whole, use the array identifier.
There are two types of arrays in JScript, JScript arrays (the Array object), and typed arrays. While the two types of
arrays are similar, there are a few differences. JScript arrays and typed arrays can interoperate with each other.
Consequently, a JScript Array object can call the methods and properties of any typed array, and typed arrays can call
many of the methods and properties of the Array object. Furthermore, functions that accept typed arrays accept Array
objects, and vice-versa.

7.1. Typed Arrays


In typed arrays (also called native arrays) you define a data type which all of the elements have to comply with. (You
can define a typed array of type Object to store data of any type.)
Also, you must define the number of elements. The only way to change the number of elements is by recreating the
array. Trying to access elements outside the range of the indexes, will generate an error. Typed arrays, are dense,
that is, every index in the allowed range refers to an element.
Use of typed arrays provides type safety and performance improvements compared to JScript Arrays.

7.1.1. Declaring Typed Arrays


Typed arrays can be declared in three different ways. We will look at these by declaring and initializing the same
typed array consisting of string values that holds the name of the days of the week in English.
The data type of the elements in a typed array is defined with the name of the data type (see Types on page 19 for
more information) followed by square brackets ([]).
One way of declaring a typed array is to list the elements separated by commas within square brackets (this is called
an array literal) :
var weekday : String[] =
["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
You can also declare an empty array, and then use the new operator to define the size of it: Use normal assignments
var weekday : String[];
weekday = new String[7];
This can also be done in one operation:
var weekday : new String[7];
To assign values to the elements of the array after declaring it as in either of the last two examples, you can use
normal assignments, referring to each of the elements of the array:
weekday[0] = "Monday";
weekday[1] = "Tuesday";
weekday[2] = "Wednesday";
weekday[3] = "Thursday";
weekday[4] = "Friday";
weekday[5] = "Saturday";
weekday[6] = "Sunday";
It is also possible to declare multidimensional typed arrays and arrays of typed arrays. Refer to a JScript .NET
reference for more information.

- 39 -
Forsta v2022 Scripting Manual Forsta Confidential

7.2. JScript Arrays


A JScript Array object provides more flexibility than a typed array. It can store data of any type, which makes it easy to
quickly write scripts that use arrays without considering type conflicts. Scripts can dynamically add elements to or
remove elements from JScript arrays. To add an array element, assign a value to the element. The delete operator
can remove elements.
A JScript array is sparse. That is, if an array has three elements that are numbered 0, 1, and 2, element 50 can exist
without the presence of elements 3 through 49. Each JScript array has a length property that is automatically updated
when an element is added. In the previous example, the addition of element 50 causes the value of the length
variable to change to 51 rather than to 4.

7.2.1. Declaring JScript Arrays


We will demonstrate the different ways of declaring and initializing JScript arrays using the same example as in the
previous chapters: An array containing the names of the seven weekdays in English.
First, declaring it using an array literal, listing the elements within square brackets, separated by commas:
var weekday =
["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
Another way is to use the new operator to create a new Array object by using the new operator, the object name
(Array) and then listing the elements of the array:
var weekday = new

Array("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sund
ay");
You can also define an empty array:
var weekday = new Array();
or an array with size 7:
var weekday = new Array(7);
and then assign values to the elements:
weekday[0] = "Monday";
weekday[1] = "Tuesday";
weekday[2] = "Wednesday";
weekday[3] = "Thursday";
weekday[4] = "Friday";
weekday[5] = "Saturday";
weekday[6] = "Sunday";
The difference between declaring the array as a JScript array instead of as a typed array (see Declaring Typed Arrays
on page 39 for more information) is that when it is defined as a typed array, all elements in the array must be of that
type.
Also, in a JScript array you can insert elements of any type, including complex types such as other arrays or objects.
Another difference is that in a JScript array you can at any time add new elements, for example another weekday.
This can be done no matter how the JScript array is defined, even when defined with the length specified, as in the
example with new Array(7).
weekday[7] = "Lastday";
(this would be a good idea to be able to at least occasionally finish projects before deadlines). The array has now 8
elements (0-7). In typed arrays, you cannot add new elements to the array, just modify existing elements.
And finally, in a JScript array you can have "holes". You can for example add a 50th element (with index 49):
weekday[49] = "Extremelyoverdueday";
without defining all the elements in between. The size of the array will be 50, even though elements with index 8,…,48
have not been defined.

- 40 -
Forsta Confidential Forsta v2022 Scripting Manual

7.3. length
The length of an array is its size, i.e. the number of elements in it. length is the index of the last element+1.
When we declared the weekday array previously, we declared an array of length 7:
var weekday = new Array(7);
The array could have been declared without specifying length:
var weekday = new Array();
Initially, the length would then have been 0, but the length would increase as elements were added. And as explained
in the previous chapter, the length will always be 1 more than the last index of the array, as the indexes start with 0.
This is true even if there are empty elements in it.
It is also possible to declare multidimensional JScript arrays and arrays of JScript arrays. Refer to a JScript .NET
reference for more information.

7.4. The length Property


As previously mentioned, JScript .NET arrays are implemented as objects. Objects are a complex data type with
collections of data that have properties and may be accessed via methods. A property returns a value that identifies
an aspect of the state of an object. Methods are used to read or modify the data contained in an object.
We will get back to objects in general in Objects, and also the methods supported by the array object (see The Array
Object on page 215 for more information).
The length of an array is a property of an array. Properties of JScript .NET objects are accessed by appending a
period and the name of the property to the name of the object:
objectName.propertyName
The length of an array is determined as follows:
arrayName.length
So if we used this in the weekday example (before adding "Lastday"),
weekday.length
would return 7.

- 41 -
Forsta v2022 Scripting Manual Forsta Confidential

8. Methods of the Form Objects


The f function used in Forsta returns objects that have a lot of different useful methods depending on the question
type. These methods can be used to reference the values, titles and answers to Forsta questions. Some of these
return strings and some return arrays of strings. Using these methods, you are able to write all sorts of scripts that
access survey variables, modify them etc. For each of the methods described, examples are given in Applying the
Methods on Different Types of Questions.
See also The f Function for further details.

8.1. get and set


f(qID).get()
f(qID).set(value)
We have seen these earlier. Used on a question q1,
f("q1").get()
will return the value stored in the database for that object. For an open text question this will be the answer the
respondent has typed in the text box, for a single question this will be the code of the answer the respondent has
selected.
f("q1").set("1");
With this statement the question q1 can be set to a specific answer. If it is a single question, it is the code value that is
set, in this case the answer with code "1". An open text question will be set to the value "1" (string) with this statement.
For multi questions and other question types with several answers (grid, ranking, open text list and numeric list
questions), get is not supported. You can use get on individual elements of these question types though (see
Referencing the Elements of a Multi, Ranking, Open Text List, Numeric List or Grid on page 57 for more information).
set can be used to set multi, grid, ranking, open text list and numeric list questions. For multi questions the method will
take the codes of the answers that should be set as input as a set, an array or as a dictionary.
f("q1").set(["1","3","4"]);
would set answers with code 1, 3 and 4 in a multi q1 as "selected", and all other answers as "not selected".
It is also possible to set a multi based on the responses to another multi:
f("q2").set(f("q1"));
For grid, ranking, numeric list and open text list, the method will take a dictionary as input, with a collection of
key/value pairs (the code of the answer and the value you want to set).
For date questions, get will return the chosen date formatted as YYYY-MM-DD, or an empty string if no date is set.
set can either take a string as parameter (format: YYYY-MM-DD) or a JScript Date object (for example f("q1").set(new
Date()) to set current date).

Note: The Date question type is only available when using the Optimized Database format.

8.2. label
f(qID).label()
This method is used to access the question title of a question. This method is available on open text, single, multi,
numeric, date, ranking, open text list, numeric listand grid questions.
f("q1").label()
will return the title of the question q1.

8.3. text
f(qID).text()
This method is used to access the question text of a question. This method is available on open text, single, multi,
numeric, date, ranking, open text list, numeric list and grid questions.

- 42 -
Forsta Confidential Forsta v2022 Scripting Manual

f("q1").text()
will return the question text of the question q1.

8.4. instruction
f(qID).instruction()
This method is used to access the question instruction of a question. This method is available on open text, single,
multi, numeric, date, ranking, open text list, numeric listand grid questions.
f("q1").instruction()
will return the question instruction of the question q1.

8.5. value
f(qID).value()
value can be used on single questions to access the code of the answer to the single question (similar to get on a
single question).

8.6. valueLabel
f(qID).valueLabel()
Use this method on a single question to access the label of the answer to the single question in the current language.

8.7. domainValues
f(qID).domainValues()
This will return an array with all codes from the answer list of a single, multi, ranking, open text list, numeric list or
grid question, headers excluded.
This method is subject to masking, so if a code mask is used to filter the answer list then this will only return the codes
of the answers that are displayed to the respondent.
The method is also subject to randomization. That is, if the answer list is randomized, then the array will be returned
randomized.

8.8. domainLabels
f(qID).domainLabels()
This method will give an array with all the labels (answer texts) on the question, headers excluded. This is the
corresponding answer texts to the codes returned with domainValues. They will be in the current language. The
method will give all possible answer texts from the answer list of a single, multi, ranking, open text list, numeric
list or grid question. This is also subject to masking.
The method is also subject to randomization. That is, if the answer list is randomized, then the array will be returned
randomized.

8.9. categories
f(qID).categories()
categories will return an array with the codes of the items that have been answered on a multi, ranking, open
text list, numeric list or grid question. For a multi question, this will be the codes of the answers that have been
selected, for a grid this will be the codes of the answers that have an answer. Usually a grid is required, so categories
will be equal to domainValues for a grid. But if the grid is not required, they may differ.

Note: If a code mask is used to filter the answer list, then this will only return the codes of those answers that
are displayed to the respondent. The f() will not return the results of a combination of answers selected by the
respondent and answers added by script.

- 43 -
Forsta v2022 Scripting Manual Forsta Confidential

Copying a Multi to do Response Piping with "Other, specify"


In the example in The Conditional Expression Ternary Operator, we saw how you could pipe in the answer in the text
box of an "other, specify" option on a single question. However, you cannot use the same approach on a multi
question because there "other, specify" can be answered in combination with any of the other alternatives.
A way of solving this for a multi question is to copy the answer of the multi question into another hidden multi question
with the same answer list, except that for "other, specify" you pipe in the response from the text box into the answer
list instead.
So if you have a multi question musicals with an "other, specify" alternative with code 98 and the "Other" property set
to yes, you can set up a second multi question musicals_hidden with the "hidden" property, where the answer from
the "other, specify" text box is piped in with the syntax
^f("musicals_98_other")^

Then you need a script node to copy the response from musicals into musicals_hidden. Copying answers from one
question to another hidden question can also be something you need to do for example to have different, shorter
answer texts in response piping in a later question, or to have different texts for reporting.
f("musicals_hidden").set(f("musicals").categories());
For this script to work, musicals and musicals_hidden need to be of the same question type and have exactly the
same answer lists (same number of items and same codes).
The script is to be placed after the musicals question:

In the info node you may now refer to the musicals_hidden question in your response piping:
You have seen these musicals: ^f("musicals_hidden")^
If the respondent for example answers like this:

- 44 -
Forsta Confidential Forsta v2022 Scripting Manual

the result of the piping will be:

8.10. categoryLabels
f(qID).categoryLabels()
This method will return an array with the labels of the items that have been answered on a multi, ranking, open text
list, numeric listor grid question in the current language, i.e. the texts from the answer list corresponding to the
codes returned from categories.

8.11. values
f(qID).values()
values will return an array with the answers stored in the database for a grid, multi, ranking, open text list or
numeric list question.

• For a grid question this will be the codes of the answers to the questions (from the scale).
• For ranking, open text list or numeric list questions it will be the numbers or texts answered for each item in
the answer list.

- 45 -
Forsta v2022 Scripting Manual Forsta Confidential

• For a multi question this will be 1 (selected) and 0 (not selected).

Note: If the multi question is hidden, then the return will be 1 (selected) and null/blank (not selected).

8.12. getType
f(qID).getType()
getType will return the type of the question. The result returned for the various question types are:

• Open text question - OPEN


• Numeric question - NUMERIC
• Single question - CODED
• Multi, ranking, open text list, numeric list and grid questions - COMPOUND
• Other specify - OPEN
• 3D-grid and multi grid - 3DGRID
• Date - DATE
• Image upload - PHOTO
• Audio upload - AUDIO_CAPTURE
• Video upload - VIDEO_CAPTURE
• Geolocation - GEO
• Boolean (property on single question) - BOOL
• A question referring to an external answer list in database designer - EXTERNAL
The getType method can be used to determine the type of question in a general purpose script for example for
validation.

Note: You cannot set the value for an Image Upload, Audio or Video Capture question.

8.13. GetAdditionalColumnValue
This is a survey engine scripting method used to retrieve data from an additional column or columns associated with a
specific table inside of a table lookup list.
f('qid').GetAdditionalColumnValue(code, additionalColumnName)
where:
code is the id to query from the lookup table.
additionalColumnName is the name of the additional column from which data is returned.
This will return the data in the specified additional column name in the table lookup for the question “qid” for the code
supplied, in the same language the interview is being completed in.
In this example where there is a single question “sales_rep” based on a database lookup “car_rep”:

- 46 -
Forsta Confidential Forsta v2022 Scripting Manual

The “salesRepDetails” info node contains the following piping of the additional columns “office” and “joined_year”:

This is achieved using the following syntax:


Your sales representative, ^f('sales_rep')^, is based in
^f('sales_rep').GetAdditionalColumnValue(f('sales_rep').get(),"office")^,
and
joined in
^f('sales_rep').GetAdditionalColumnValue(f('sales_rep').get(),"joined_yea
r")^.

Note: In most cases the code value supplied in the method will refer to the f(‘qid’).get() for the question that
the lookup is based on.

You can perform a test to check whether the code exists in the table used as qid’s answerlist. If the code doesn't exist
in the table lookup then the method will return "undefined".
To test if the code exists in the table lookup, and display an error message if not, add the following:
if(f('qid').GetAdditionalColumnValue(code,additionalColumnName)==undefine
d)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,”Error – that code doesn’t exist in
the lookup table”);
}

Note: The GetDBColumnValue function is described here (see GetDBColumnValue on page 98 for more
information).

8.14. any
f(qID).any(code1,…,coden)

- 47 -
Forsta v2022 Scripting Manual Forsta Confidential

any will return true if any of the codes listed is answered on a single or multi question, or if any of the items for these
codes have a response on a grid, multi, ranking, open text list or numeric list question, or false if none of these
items has a response. The method is for example useful in conditions.

8.15. all
f(qID).all(code1,…,coden)
all will return true if all of the codes listed is answered on a multi question, or if all of the items for these codes has a
response on a grid, multi, ranking, open text list or numeric list question, or false if none of these items has a
response. The method is for example useful in conditions.

8.16. none
f(qID).none(code1,…,coden)
none will return true if none of the codes listed is answered on a single or multi question, or if none of the items for
these codes has a response on a grid, multi, ranking, open text list or numeric list question, or false if either of
these items has a response. The method is for example useful in conditions.

8.17. between
f(qID).between(from, to)
between will return true if the answer to a numeric question or an item of a numeric list question is between the
from value and the to value, or false if not. This means the value answered is higher than or equal to the from value
and lower than or equal to the to value. The method is for example useful in conditions.

8.18. isNearBy
f(qID).isNearBy(latitude, longitude, distance)
isNearBy can be used on Geolocation questions, and will return true if the position recorded in the question is within a
given distance in meters from the position defined by the latitude and longitude. Latitude, longitude and distance are
all numeric (double).

8.19. latitude and longitude


f(qID).latitude()
f(qID).longitude()
Latitude and longitude can be used on Geolocation questions, and will return the latitude and longitude of the position
recorded in the question.

8.20. Applying the Methods on Different Types of Questions


The examples below show these methods applied on an open text, date, single, single with Boolean property set,
multi, open text list, and grid question. Each question is followed by an info node that is set up with response piping
using the different methods.

- 48 -
Forsta Confidential Forsta v2022 Scripting Manual

8.20.1. Open Text Question


Question ID: "name".

8.20.2. Date
Question ID: "birthday".

- 49 -
Forsta v2022 Scripting Manual Forsta Confidential

The date format will depend on survey language.

Note: The Date question property is only available when using the Optimized Database format.

8.20.3. Single Question


Question ID: "gender". Codes: M (Male) and F (Female).

- 50 -
Forsta Confidential Forsta v2022 Scripting Manual

8.20.4. Single Question with Boolean Property Set


Question ID: "license". Single questions with the Boolean property set will be fixed to having two answers in the
answerlists with code 1 (true) and 0 (false).

- 51 -
Forsta v2022 Scripting Manual Forsta Confidential

Note: The Boolean question property is only available when using the Optimized Database format.

8.20.5. Multi Question


Question ID: "cars". Codes: "1","2","3","4","5","6","7".

- 52 -
Forsta Confidential Forsta v2022 Scripting Manual

8.20.6. Open Text List


Question ID: "carscharacteristics". Codes: "1","2","3","4","5","6","7".

- 53 -
Forsta v2022 Scripting Manual Forsta Confidential

8.20.7. Geolocation Question


Question ID: "position"

- 54 -
Forsta Confidential Forsta v2022 Scripting Manual

8.20.8. Grid Question


Question ID: "importance". Codes in answer list: "1","2","3","4","5","6","7". Code in scale: "1","2","3","4".

- 55 -
Forsta v2022 Scripting Manual Forsta Confidential

8.20.9. Other Specify Items


Single, Multi, Numeric Lists, Open Text Lists, Ranking, Grid and 3D Grid questions can all have elements in the
answer list with the "Other" property set. This means the answer alternative will be presented with a text box such that
the respondent can specify an "other" answer alternative.
You refer to this response with the id qID_code_other, for example q1_98_other for the other text box for answer
alternative with code 98 on question q1. Here, for the other, specify alternative on a multi question cars:

- 56 -
Forsta Confidential Forsta v2022 Scripting Manual

8.20.10. Referencing the Elements of a Multi, Ranking, Open Text List, Numeric
List or Grid
Each item in the answer list of a multi, ranking, open text list, numeric list or grid can be referenced with syntax quite
similar to the syntax for referencing the items in an array. But instead of a numeric index starting at zero, you refer to
the elements of a multi or a grid by using the code of the element. The code is a string. For example
f("q1")["3"]
will be the item with code "3" in the multi or grid q1.
When you use this syntax to access an element of a grid or a multi, you can use the following methods:

• get, set, label and getType for the elements of a multi, ranking, open text list or numeric list question.
label will then give the label of the answer in the current language. getType will return "DICHOTOMY" if it is
a multi, "NUMERIC" if it is a numeric list, and "OPEN" if it is any of the other types.
• get, set, label, value, valueLabel, domainValues, domainLabels for the elements of a grid
question. label will then give the label of the answer (from the answer list) in the current language. value
will return the code of the answer (from the scale) to that element of the grid. valueLabel will return the
corresponding answer text (from the scale) in the current language. domainValues and domainLabels will
respectively return all possible codes from the scale and the corresponding labels (answers) from the scale in
the current language. getType will return "CODED".
Using the same multi and grid from the previous example, the examples below show methods that can be used on the
single elements of a multi or a grid.

- 57 -
Forsta v2022 Scripting Manual Forsta Confidential

8.20.10.1. Element of a Grid Question

8.20.10.2. Element of a Multi Question

8.20.10.3. Element of an Open Text List Question

8.20.11. Loops
The same methods may be used on a loop node as on a single question. They return the same items as the single,
except for label, which will return the loop's ID (not the loop's title, which is only used in reporting).

- 58 -
Forsta Confidential Forsta v2022 Scripting Manual

Below are the results from the first iteration of the loop:

The first four methods (get, label, value and valueLabel) can only be used inside the loop and will give results
for the current iteration. domainValues and domainLabels can also be used outside of the loop.

8.20.12. 3D Grid
None of the methods apply directly to 3D grids. Instead, refer to the questions contained in the 3D grid by their
question IDs.
An other specify item on a 3D grid can be accessed in a similar way to other specify on other questions:
f("qid_code_other").get()
qid would then be the question id of the 3D grid, and code would be the code of the answer with other specify.

8.20.13. Implicit Conversion of Arrays to Strings


The arrays in the previous examples are all presented in a string context (text substitution with ^) so they are
converted into strings. When an array (the result from applying categories, categoryLabels, values,
domainValues or domainLabels) is converted into a string, the elements are presented separated by commas.
Exercise 4:
In this grid, where the default codes ("1","2","3",…) are used both in answers and in scale, what methods do you have
to use on
f("importance")["2"]
to get the label

1. "Important"

- 59 -
Forsta v2022 Scripting Manual Forsta Confidential

2. "Design"

The answers are given in APPENDIX A Answers to Exercises.

8.21. Overview – Methods of Basic Variable Objects in Forsta

Open Date Nume Single Multi Open Nume Ranki Grid Geoloc Element Eleme Loop
text ric Text ric ng ation of multi, nt of
List List open text grid
list,
numeric
list,
ranking
String .get () X X X X X X X X
.set () X X X X X X X X X X X X X
.label () X X X X X X X X X X X X X
.text () X X X X X X X X X X
.instruction X X X X X X X X X
()
.value () X X X X X X
.valueLabel X X X
()
.getType X X X X X X X X X X X X X
Array .domainVal X X X X X X X X
ues ()
.domainLab X X X X X X X X
els ()
.categories X X X X X
()
.categoryLa X X X X X
bels ()
.values () X X X X X
.any() X X X X X X

- 60 -
Forsta Confidential Forsta v2022 Scripting Manual

Boole .all() X X X X X
an .none() X X X X X X
.between() X X1
.isNearBy() X
Doubl .latitude() X
e .longitude() X

1 numeric list item only.

- 61 -
Forsta v2022 Scripting Manual Forsta Confidential

9. Loop Statements
Loop statements are used to repeat the execution of a set of statements as long as a particular condition is true.
There are three types of loop statements in JScript .NET: the while statement, the do while statement and the for
statement. The loop statements in JScript .NET are similar to the loop construct in Forsta, but there is a difference: In
a loop in Forsta, a set of questions is repeated for the items in the loop list (subject to masking). In a JScript .NET
loop, a set of statements is repeated until a condition is evaluated to false.

9.1. The while Statement


while ( condition )
{
statements
}
The while statement evaluates the condition, and if the condition evaluates to true, executes the statements
enclosed within brackets. When the condition evaluates to false, it transfers control to the statement following the
while statement.

Validating Sums in a 3D Grid Using a while Loop


In the following example, the while statement is used in the validation code of a 3D grid to check that the sum for
each row is 24:

The 3D grid contains 3 numeric list questions: q2 (sleep), q3 (work) and q4 (leisure).
The following code is entered in the validation code field to evaluate the respondent's answers:

- 62 -
Forsta Confidential Forsta v2022 Scripting Manual

var codes = f("q2").domainValues(); //array with all codes


var i : int = 0;
var correctSum : Boolean = true; //Boolean variable. Will be set to false
when a sum is not correct
while(i<codes.length && correctSum)
{
var code = codes[i]; //current code
//calculate the sum for one row:
var sum : int =

f("q2")[code].toNumber()+f("q3")[code].toNumber()+f("q4")[code].toNumber(
);
if(sum != 24)
{
correctSum = false;
}
i++;
}
if(!correctSum)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please make sure that the total
number of hours for each day equals 24. Currently the sum for
"+f("q2")[code].label()+" is "+sum+".");
}
Let us see what actually happens here when the question is answered as in the picture above.
The first statement,
var codes = f("q2").domainValues();
declares an array called codes, which contains all the codes from the answer list of q2. (Since q2, q3 and q4 are all
inside the same 3D grid, they share the same answer list, so we could have used any of these questions to populate
the array.) We have used the default codes ("1","2","3","4","5","6","7") in this answer list, so the first statement
declares an array of length 7 where the items have the following values:
codes[0] = "1"
codes[1] = "2"
codes[2] = "3"
codes[3] = "4"
codes[4] = "5"
codes[5] = "6"
codes[6] = "7"
The main advantage with using domainValues here is that we can do any changes we like to this answer list
(including adding/removing items and changing the codes) without having to change the script.
Then in the next statement we declare a new variable i as an integer with the initial value 0 (zero). This will be used
to index the array. After that the Boolean correctSum is declared with the initial value true.
var i : int = 0;
var correctSum : Boolean = true;
So, when we enter the while loop the first time, the condition will evaluate to true because i is 0, which is less than
the length of the array codes (which is 7), and correctSum is true.
while(i<codes.length && correctSum)
With i equal to 0, the first statement
var code = codes[i];
will set code to the first code, "1".
A variable sum is then set in the statement

- 63 -
Forsta v2022 Scripting Manual Forsta Confidential

var sum : int =

f("q2")[code].toNumber()+f("q3")[code].toNumber()+f("q4")[code].toNumber(
);
to 7+8+9, which is 24. (This is the numbers entered for Monday in the 3D grid, see screenshot above.)
The condition in the following if statement will evaluate to false, so the statement inside the curly brackets will not
be executed. Consequently, correctSum will remain true:
if(sum != 24)
{
correctSum = false;
}
At the end of the loop i is increased by 1:
i++;
That completes the first iteration of the while statement. The next time the condition in the while statement is
evaluated, i is 1. 1 is less than 7, and correctSum is still true, so the condition still evaluates to true, and the
statements are to be run a second time.
while(i<codes.length && correctSum)
With i equal to 1, the first statement
var code = codes[i];
will set code to the second code, "2".
The sum will now be 7+11+6 (Tuesday), which is 24.
var sum : int =

f("q2")[code].toNumber()+f("q3")[code].toNumber()+f("q4")[code].toNumber(
);
The condition in the if statement will again evaluate to false (so correctSum will not be changed), and  is
increased by 1 at the end of the loop:
if(sum != 24)
{
correctSum = false;
}
i++;
The third time the condition in the while statement is evaluated, i is 2. 2 is less than 7, and correctSum is true.
The condition evaluates to true, and the statements are to be run a third time.
while(i<codes.length && correctSum)
i is now 2, and code will be set to the third code, "3":
var code = codes[i];
The sum will now be 8+9+8 (Wednesday), which is 25.
var sum : int =

f("q2")[code].toNumber()+f("q3")[code].toNumber()+f("q4")[code].toNumber(
);
Now the condition in the if statement will yield true because 25 is not equal to 24. So this time correctSum will be
set to false.
if(sum != 24)
{
correctSum = false;
}

- 64 -
Forsta Confidential Forsta v2022 Scripting Manual

Then at the end i is increased to 3.


i++;
The fourth time the condition in the while statement is evaluated, the first part will be true because 3 is less than 7,
but correctSum is now false, so the entire expression will give false. So this time the execution of the loop will
end.
while(i<codes.length && correctSum)
Since correctSum is now false, the condition in the following if statement will evaluate to true and the two
statements inside will be executed. The statements are calling functions to identify this as an error situation, and to
display an error message. We will get back to functions later, also showing a function that would make it easier to
calculate the sum.
if(!correctSum)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please make sure that the total
number of hours for each day equals 24. Currently the sum for
"+f("q2")[code].label()+" is "+sum+".");
}

9.2. The do while Statement


The do while statement is similar to the while statement. The only difference is that the looping condition is
checked at the end of the loop, instead of at the beginning. This means that the enclosed statements are executed at
least once. The condition is not evaluated before after the statements are executed the first time.
do
{
statements
}
while (condition);
This may be used for example when the condition uses variables that aren't introduced before inside the loop. In the
example below the variable correctSum is not introduced before inside the loop.

Validating Sums in a 3D Grid Using a do while Loop


Using the same example as in Validating Sums in a 3D Grid Using a while Loop, this code would give the same
validation of the 3D grid:
var codes = f("q2a").domainValues(); //array with all codes
var i : int = 0;
do
{
var code = codes[i]; //current code
//calculate the sum for one row:
var sum : int =

f("q2a")[code].toNumber()+f("q3a")[code].toNumber()+f("q4a")[code].toNumb
er(); var correctSum : Boolean = (sum == 24); //false if sum not 24,
true if sum is 24
i++;
}
while(i<codes.length && correctSum)

if(!correctSum)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please make sure that the total
number of hours for each day equals 24. Currently the sum for
"+f("q2a")[code].label()+" is "+sum+".");
}

- 65 -
Forsta v2022 Scripting Manual Forsta Confidential

9.3. The for Statement


The for statement is similar to the while statement in that it repeatedly executes a set of statements while a
condition is true. The difference is that the syntax of the for loop includes both an initialization statement and an
update statement in its syntax:
for (initializationStatement; condition; updateStatement)
{
statements }
The initialization statement is executed at the beginning of the loop execution. Then the condition is tested, and if it is
true, the statements enclosed within brackets are executed. If the condition is false, the loop is terminated and the
statement following the for statement is executed. If the statements enclosed within the brackets of the for
statement are executed, the update statement is also executed, and then the condition is reevaluated. So the
enclosed statements and the update statement are repeatedly executed until the condition becomes false.
Typically the initialization statement declares an integer with an initial value, and the update statement increases or
decreases this integer. The condition then usually defines the limit.

Validating Sums in a 3D Grid Using a for Loop


In the previous examples, we stopped validating sums as soon as we found the first error. Here is an example using
the for statement where we validate all rows and provide an error message listing all rows with errors.

The 3D grid contains 3 numeric list questions: q2 (sleep), q3 (work) and q4 (leisure). In addition we have a hidden
multi question error_rows which is used to set which rows have incorrect sums.
The following code is entered in the validation code field to evaluate the respondent's answers:

- 66 -
Forsta Confidential Forsta v2022 Scripting Manual

var precodes = f("q2").domainValues(); //array with all precodes


var error_rows = new Array();
for(var i = 0;i<precodes.length;i++)
{
var code = precodes[i]; //current precode
//calculate the sum for the row:
var sum : int =
f("q2")[code].toNumber()+f("q3")[code].toNumber()+f("q4")[code].toNumber(
);
if (sum != 24)
error_rows.push(precodes[i]);
}
if(error_rows.length>0)
{
f("error_rows").set(error_rows);
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please make sure that the total
number of hours for each day equals 24. Please correct for the following
rows: "+f("error_rows").categoryLabels()+".");
}
(The push method is used to add elements to an array (see Removing and Adding Elements on page 216 for more
information)).

9.4. Loop Nodes


You can build loops in Forsta if you want to ask the same question(s) for different elements. The loops can be nested.
For example, we can have a loop that iterates through some TV channels asking a question for each TV channel
about what kind of programs the respondent watches on the different channels. Then, for those program types there is
another loop inside the first one in which they are asked to rate those programs for each channel.
The inner loop is called programs and is placed inside the loop called channels. In the inner loop we have a single
question called rating in which we want to ask the respondent about the program types he/she has specified in types
(the multi question in the outer loop). So the programs loop uses the same list of program types as the types question,
and the loop is filtered with a code mask based on the types question, f("types"). So the loop will only iterate
through the program types answered for a specific channel.

In scripts inside the loops you can refer to the questions as usual, e.g. f("types"). This will refer to that question in
the current iteration of the loop. However, if you need to refer to questions in the loops from scripts outside of the
loops, you have to specify which iteration you refer to.
For example, f("types","1") refers to the question called types in the iteration with code 1 within this loop. With
nested loops (like we have here), you specify the innermost iteration first, so f("rating","3","1") refers to the
rating question from the iteration with code "3" of the inner loop programs. For the outer loop channels it is the
iteration with code "1".

9.5. The break Statement


break;
Sometimes you want to terminate the execution of the loop before it is finished (before the condition in the loop
statement evaluates to false). Then you may use the break statement. The break statement will terminate
execution of the loop and transfer control to the statement following the loop.

Validating Sums in a 3D Grid Using a for Loop and break


The example we used for the while loop can be programmed using a for loop and a break like this:

- 67 -
Forsta v2022 Scripting Manual Forsta Confidential

var codes = f("q2b").domainValues(); //array with all codes


for(var i : int = 0; i<codes.length; i++)
{
var code = codes[i]; //current code
//calculate the sum for one row:
var sum : int =
f("q2b")[code].toNumber()+f("q3b")[code].toNumber()+f("q4b")[code].toNumb
er();
if(sum != 24)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please make sure that the total
number of hours for each day equals 24. Currently the sum for
"+f("q2b")[code].label()+" is "+sum+".");
break; //terminate execution of the loop when an error is found
}
}
When a row for which the sum is not equal to 24 is found, the loop will terminate without going through the last
iterations.

9.6. The continue Statement


continue;
The continue statement is similar to the break statement, but instead of transferring control to the statement after
the loop it terminates the execution of the current iteration and skips to the next iteration of the loop (after checking the
loop condition).

Calculating Averages in a Grid


We have a grid question course, and for reporting we want to calculate an average of the answers to the grid and
store it in a hidden numeric question called average. The grid uses a 5 points scale (and 6 as a value for "Don't
know"). Obviously, we want the average to be calculated based on the questions with answers 1-5. The “Don’t know”s
(6) should not be included in the calculation.

- 68 -
Forsta Confidential Forsta v2022 Scripting Manual

var codes = f("course").domainValues(); //all codes of the rows in the


grid
var sum : int = 0; //this will hold the sum of the scores
var count : int = 0; //this will hold the number of items
for(var i : int = 0;i<codes.length;i++) //iterate through the rows in
the grid
{
var code = codes[i]; //current code
if(f("course")[code].get() == "6") //don't know
{
continue; //skip directly to next iteration
}
//here we know that the answer isn't don't know
sum += f("course")[code].toNumber(); //add current score to sum
count++; //increase counter with one
}
if(count>0) //prevent division with zero
{
f("average").set(sum/count); //calculate average
}
else
{
f("average").set(null); //set null value if answered "don't know" on
all
}
If the respondent has answered "don’t know" (code 6) on one of the questions, the last two assignment statements
are skipped because of the continue, so sum and count will not be updated for "Don't know" answers.

9.7. The label Statement/Nested Loops


Sometimes you need to specify exactly where execution is to continue after a break or a continue is used.
Especially when you have nested loops (loops in loops). To specify which loop you want the break or continue to
apply to, you can specify a label and refer to that in your break or continue statement. The names of labels follow
the same rules as variable names (see Naming on page 16 for more information).
Specifying a label:
label:
Referring to a label:
break label;continue label;

Calculating Averages on a Single Question in a Loop


Referring back to the example with two nested loops in Forsta (see Loop Nodes on page 67 for more information),
One iterating through some TV channels, and the other iterating through some types of programs:

For each channel, the respondent answer what type of programs they watch on that channel, and then give a rating
for each program type for that channel in the rating question. Now we want to write a script that calculates an average
of these ratings for each channel. Here is the list of iterations in the channels question:

- 69 -
Forsta v2022 Scripting Manual Forsta Confidential

We set up a hidden numeric list question avg with the same list:

Now, after the loop we insert a script node to calculate these averages.

This script must run through all the items in the channels loop, and for each of them run through all the ratings
given in the programs loop:

- 70 -
Forsta Confidential Forsta v2022 Scripting Manual

var ccodes = f("channels").domainValues(); //all codes of the channels


loop
Outer:
for(var i : int = 0;i<ccodes.length;i++) //iterate through channels
{
var ccode = ccodes[i]; //code of current channel
//initialize the counter and sum for this channel:
var sum : int = 0, count : int = 0;

//the codes of the program types for this channel:


var pcodes = f("types",ccode).categories();
Inner:
for(var j : int = 0;j<pcodes.length;j++) //run through the codes in the
programs loop
{
var pcode = pcodes[j]; //code of current program type
//check rating for this program type for this channel:
if(f("rating",pcode,ccode).get() == "6")
{
continue Inner; //go to next program type
}
sum += f("rating",pcode,ccode).toNumber(); //add score to sum
count++; //increase counter with one
}
//set average score for this channel:
if(count>0)
{
f("avg")[ccode].set(sum/count);
}
else
{
f("avg")[ccode].set(null);
}
}
This example uses nested loops (loops in loops), i.e. one outer loop that iterates through the channels loop and one
inner loop that iterates through the answers in the programs loop. We have used the labels Inner and Outer in the
script to make sure that it is the iteration of the inner loop that is terminated with the continue, not the iteration of the
outer loop. (We do not actually refer to the label Outer anywhere in the script, but we have included the label for
clarity.)
Exercise 5:
Write a script that presets a grid question q2, which has a scale from 1 to 5, so that the first time the respondent
comes to that question, all rows in the grid have been set to the middle value 3. Make sure that the values are not
reset if the respondent reopens the questionnaire or uses the back button.
The answer is given in APPENDIX A Answers to Exercises.

- 71 -
Forsta v2022 Scripting Manual Forsta Confidential

10. Functions
Usually, when using scripts you reuse a lot of code. Instead of copying the entire code, you can define a function with
that code and call it when you need it.
Functions combine several operations under one name. This lets you streamline your code. You can write out a set of
statements and define the block of statements as a function and give it a name. Then the entire block of statements
can be executed by calling the function and passing in any information the function needs. If a function is given a
name that describes what it does, it will be easier to read and understand the code. It will hide details and make your
scripts more modularized.
You pass information to a function by enclosing the information in parentheses after the name of the function. Pieces
of information that are passed to a function are called arguments or parameters. Some functions do not take any
arguments at all while others take one or more arguments. In some functions, the number of arguments depends on
how you are using the function.
A function call is a statement used to invoke a function. Use the function name followed by parentheses containing the
arguments, if any, to do a function call:
FunctionName(p1,p2,...,pn)
You always have to use the parentheses, even if a function contains no arguments:
FunctionName()
A function may or may not return a value.

10.1. Built-in Functions


Let us start by looking at the functions provided in Forsta.

10.1.1. Arithmetic Functions


10.1.1.1. Sum
Sum( arguments )
Sum returns the sum of its arguments. Valid argument types are numbers, strings, arrays or any kind of object. Use
comma to separate the arguments.

Validating Sum on a Numeric List Question


Here is an example of a numeric list question, in which the respondents are asked to apply percentages that should
sum up to 100. You can use the "Auto sum" property to have the sum calculated and displayed directly below the
respondent's answers.

- 72 -
Forsta Confidential Forsta v2022 Scripting Manual

The question id of the numeric list question is percentage. In properties total digits is set to 3, scale to 0, and lower
and upper limit to 0 and 100, so that the system provided validation makes sure that only integers between 0 and 100
is allowed. To validate that the answer is equal to 100, you can use the Force sum of answers setting in the question
properties, or use the following code in the validation code field of the question:
var sum : int = Sum(f("percentage").values());

if(sum!=100)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en, "Your numbers add up to " + sum + ".
Please make sure that the numbers add up to 100.")
}

Validating Sums in a 3D Grid with the Sum Function


Let us go back to the example with the validation script that checked that the respondent answered a total of 24 hours
for each day (see the examples in The While Statement, The Do While Statement, and The Break Statement for
details).

- 73 -
Forsta v2022 Scripting Manual Forsta Confidential

In the code of that example we used the expression


sum =
f("q2")[code].toNumber()+f("q3")[code].toNumber()+f("q4")[code].toNumber(
);
to add up the number of hours. Instead we could use the Sum function, like this
sum = Sum(f("q2")[code],f("q3")[code],f("q4")[code]);
Notice that the Sum function automatically converts the values to numeric, so we do not need to use the toNumber
method.
Then the entire validation code will look like this, if we use the solution with the while loop:

- 74 -
Forsta Confidential Forsta v2022 Scripting Manual

var codes = f("q2").domainValues(); //array with all codes


var i : int = 0;
var correctSum : Boolean = true; //Boolean variable. Will be set to false
when a sum is not correct
while(i<codes.length && correctSum)
{
var code = codes[i]; //current code
//calculate the sum for one row:
var sum : int = Sum(f("q2")[code],f("q3")[code],f("q4")[code]);
if(sum != 24)
{
correctSum = false;
}
i++;
}
if(!correctSum)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please make sure that the total
number of hours for each day equals 24. Currently the sum for
"+f("q2")[code].label()+" is "+sum+".");
}

10.1.1.2. Count
Count( arguments )
Count returns the number of arguments. Valid argument types are numbers, strings, arrays or any kind of object. Use
comma to separate the arguments. An array will be split into its elements, so used on an array Count will return the
number of elements in the array.

Finding the Number of Answers on Three Multi Questions


We have three multi questions; officesa, officesb and officesc. This could for example be a question in an employee
survey for an international company with offices all around the world, where we want to split the list of offices on three
different questions on three different pages.

- 75 -
Forsta v2022 Scripting Manual Forsta Confidential

If you want to find the number of items answered on all three questions combined, for example for use in a condition
to ask some further question(s) only if the respondent has answered more than one office, you can use the Count
function:
Count(f("officesa").categories(),f("officesb").categories(),f("officesc")
.categories()) > 1
If the respondent has picked 2 offices on q1, 1 office on q2 and 3 offices on q3, the result of this function call will be
the value 6 (2+1+3).

10.1.1.3. Average
Average( arguments )
Average returns the average (mean) of its arguments. Valid argument types are numbers, strings, arrays or any kind
of object. Use comma to separate the arguments.

Calculating Averages on 3 Numeric List Questions in a 3D Grid


Again referring to the example with the hours and the weekdays, let us say we want to set three hidden numeric
questions sleep, work and leisure with the daily average for each of them.
We use the Average function:

- 76 -
Forsta Confidential Forsta v2022 Scripting Manual

f("sleep").set(Average(f("q2").values()))
f("work").set(Average(f("q3").values()))
f("leisure").set(Average(f("q4").values()))
(The 3D grid consisted of three numeric list questions, q2 for sleep, q3 for work and q4 for leisure). The hidden
question sleep for instance, will here be set to 8 since 56/7 is 8 (see Sum on page 72 for more information).

10.1.1.4. Max and Min


Max( arguments )
Min( arguments )
Max returns the maximum (the largest value) of its arguments. Min returns the minimum (the smallest value) of its
arguments. Valid argument types are numbers, strings, arrays or any kind of object. Use comma to separate the
arguments.

Finding Maximum and Minimum Values on Numeric List Questions


Once again, referring to the "hours and weekdays" (see Sum on page 72 for more information), let us say we want the
maximum number of work hours in the week (stored in a hidden question maxwork) and the minimum number of
hours sleep in the week (stored in a hidden question minsleep):
f("maxwork").set(Max(f("q3").values()))
f("minsleep").set(Min(f("q2").values()))
In the example (see Sum on page 72 for more information), maxwork will get the value 12 and minsleep the value 5.

10.1.2. Range
Range has two alternatives:
InRange(arg,min,max)
InRange returns true if arg is within the range (min, max) (inclusive).
InRangeExcl(arg,min,max)
InRangeExcl returns true if arg is within the range (min, max) (exclusive).

Building a Condition on a Range of Codes


You may need your conditions to work for several codes within a range. For example, you may have an age question
where this is a part of the answer list:

If you wanted some questions to be sent only to people between the ages of 26 and 50, you could use a condition
with an expression as follows:

- 77 -
Forsta v2022 Scripting Manual Forsta Confidential

f("age").toNumber() >= 4 && f("age").toNumber() <= 8


but in this case it will be easier to use the InRange function:
InRange(f("age"),4,8)

10.1.3. Context Information


10.1.3.1. GetSurveyChannel
GetSurveyChannel()
GetSurveyChannel is used to show which channel the survey is being executed on. A String value indicates the
channel type as listed below:

String returned Description

Capi CAPI interview


Cati CATI interview
Cawi Web interview
RandomDataGeneration Response is generated using Random Data Generator
SDK Mobile App SDK survey
SelfCompletionSurvey Self completion interview (via AskMe app)

This function can for example be used to store the channel in a hidden single question channel by setting it in a
script node:
f("channel").set(GetSurveyChannel())
Another example is to use it inside a condition to ask certain questions only to web respondents:

A third example is to use it to display certain texts only when the interview is performed by an interviewer (CAPI or
CATI):

- 78 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.3.2. IsInProductionMode
IsInProductionMode()
IsInProductionMode() can be used to distinguish between running surveys in production mode or in quick test/external
quick test/test mode. It will return one of the following values:

true Production mode


false Quick Test/External Quick Test/Test mode

10.1.3.3. GetRenderingMode
GetRenderingMode()
GetRenderingMode() can be used to determine whether desktop rendering, one of the mobile rendering modes (touch
or generic), is currently active in the survey. This function can for example be used in a condition if you would like
certain questions only to be presented in the desktop version of the survey. If responsive rendering is activated,
GetRenderingMode will return "responsive".
To get the mobile rendering modes (touch and generic), these modes must be active on the survey.

desktop Desktop rendering (PC/Mac/tablet)


responsive Responsive rendering mode
touch iPhone/iPod touch/Android phones
generic All other mobile phones

If you for example want to provide some questions only to users accessing a survey through the desktop rendering,
you can use the following expression in a condition, and then place those questions inside the Then branch:
GetRenderingMode() == "desktop"

10.1.3.4. GetContentType
GetContentType()
GetContentType()can be used to distinguish between surveys run as regular Web surveys or through a Flex extension
using the Survey Front End extension point, such as iPhone, Android and SMS surveys. It will return one of the
following values:

- 79 -
Forsta v2022 Scripting Manual Forsta Confidential

Html Run as a regular web survey


Json Run using the Flex Survey Front End extension point using Json
Xml Run using the Flex Survey Front End extension point using Xml

10.1.3.5. AdvancedWIFeaturesEnabled
AdvancedWIFeaturesEnabled()
AdvancedWIFeaturesEnabled() is used to determine whether the respondent’s browser supports Advanced WI
Features that require client side scripts, such as sliders, drag-n-drop ranking, images instead of radio-buttons/check-
boxes etc. It will return true if the respondent’s browser supports the advanced WI features, or false if not. It can for
example be used to display a different instruction text depending on whether or not respondents will have a question
displayed with the advanced WI interface.
This function is optimistic with regards to checking whether JavaScript is turned on or off in the browser. In other
words it will return true unless it is determined that JavaScript is turned off.

Note: This state can only be determined once the respondent has opened the first page of the survey. This
function must therefore be executed after the first page of the survey.

Displaying different instruction if Advanced WI feature is being used


If you have a question using the drag-n-drop ranking feature, you may present two different instruction to respondents:
One for respondents that have a browser supporting the drag-n-drop interface, and another one to respondents that
do not have a browser supporting these. The latter will then get the question with ordinary input boxes where they can
rank with numbers.
This can be done by using a ternary conditional expression with the AdvancedWIFeaturesEnabled function in the
instruction text field of the questionnaire.
^AdvancedWIFeaturesEnabled() ? "Please rank the cars by dragging them
over to the right hand side, the first indicating the one your are most
likely to buy and so on" : "Please rank the cars by entering numbers in
the text boxes. 1 for the car your are most likely to buy, 2 for the
second most likely and so on"^

10.1.3.6. DynamicQuestionsEnabled
DynamicQuestionsEnabled()
DynamicQuestionsEnabled() is used to determine whether the respondent’s browser supports AJAX so that the
“Dynamic Questions” functionality can be used (see Dynamic Questions on page 11 for more information). It will
return true if the respondent’s browser supports AJAX, or false if not. It can for example be used for screening
respondents from a survey that have extensive usage of .this, or in a condition to provide an alternative path for
respondents, if they have a browser that does not support it. Unlike “Advanced WI Features”, no fallback (i.e.
alternative interface) exists for this functionality.

10.1.3.7. IsDynamicQuestionCallback
IsDynamicQuestionCallback()
IsDynamicQuestionCallback is used to determine whether the code is currently executed during a Dynamic Question
Callback, i.e. an Ajax update of one or more Dynamic Questions. This will be true if used within a question that has a
trigger, when one or more of the trigger questions is updated.

- 80 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.3.8. IsInlineSurveyCallback
IsInlineSurveyCallback()
IsInlineSurveyCallback is used to determine whether the survey is currently run as an inline survey.

For "regular" surveys, the response record is created when the respondent opens the first page of the survey (this is
the default). However for inline surveys, the response record is created when the respondent submits the first page of
the survey. This is done to reduce the amount of empty data records, since an inline survey may be placed within high
volume sites where only a small percentage of the visitors will submit a response.
It is therefore not possible to use the .set() method in a script within the first page to store responses when the survey
is running inline, because the data cannot be stored in the database since the database record does not yet exist.
Such scripts can only be run from the second page onwards.
If you need to retrieve values from the query string using Request (see Request on page 228 for more information)
and store in the database, you will have to do this on the second page. In inline mode the query string is preserved
when moving from the first to the second page.
If the survey is accessed both in inline mode and as a regular survey link, you do have to treat these modes
differently, and the IsInlineSurveyCallback function can be used for this. Let's say you send in a value site=1. At the
start of the survey you can add this script to fetch the value when the regular survey link is opened:
if(Request("site")!=null &&!IsInlineSurveyCallback())
{
f("site").set(Request("site"));
}
Before the second page, you can insert the following script to fetch the value when the survey is inline:
if(Request("site")!=null &&IsInlineSurveyCallback())
{
f("site").set(Request("site"));
}

10.1.3.9. CurrentForm
CurrentForm()

- 81 -
Forsta v2022 Scripting Manual Forsta Confidential

CurrentForm is used in validation code, masking and in response piping in a question's text fields (or in functions
called from validation code, masking and response piping) and returns the question ID (string) of the current question.
Used inside the validation code field of one of the questions inside a 3D grid, it will give the question id of that
question instead of the id of the 3D grid itself.
You can use this to write generic code that can be reused without having to change the question ID.

Note: For questions within a 3D-grid, CurrentForm works only in validation code scripts. For piping or other
scripts within a 3D-grid the evaluation depends on the execution context, so CurrentForm will not function
correctly.

10.1.3.10. GetRespondentUrl
GetRespondentUrl()
GetRespondentUrl(string qid)
GetRespondentUrl(string qid, params string[] loopQual)
GetRespondentUrl(string id, bool isCallBlock)
GetRespondentUrl(string id, bool isCallBlock, string parameters)
GetRespondentUrl(string id, bool isCallBlock, string parameters, params
string[]loopQual)
Where:
qid is a question id.
id is either a question id or a callbock id.
isCallBlock denotes whether the id is a question id or a callblock id.
parameters is a string to be passed into the survey in the url; the string can contain one or more parameters;
where more than one parameter is being used a semi-colon should be used as a separator.
loopQual is only applicable when the question id exists within one or more loops and the url is being used to
direct the respondent to a particular iteration.
GetRespondentUrl returns a URL that will allow the current interview to be entered at a specific point.
All of the parameters are optional. If they are not used the URL will, depending on the Survey Settings, take the user
either to the beginning of the interview or to the last question where they left off. But when they are used, they can
provide the following capabilities:

1. The respondent can be directed to the page of a particular question, and, if the question is inside one or more
loops, a particular loop iteration or iterations. The interview will then continue from that point.
2. The respondent can be directed to a particular callblock which, upon completion of the callblock, will finish the
interview.
3. The function can securely pass a text value or several text values into the start of the interview, that will then
be accessible via the UserParameters function.
GetRespondentUrl can be used for example to send an email to the respondent to allow him/her to re-access the
survey, or it can be presented inside the survey so that the respondent can copy it to return to the survey later.
To follow are some examples of different combinations of the optional parameters, and cases where they may be
used.
In this example,
GetRespondentUrl("q9")
will give a link that when opened, will open the survey for the current respondent on the page with q9, and then
continue through the interview. This could also be written as:
GetRespondentUrl("q9", false)
which will have the exact same effect.
In this example,

- 82 -
Forsta Confidential Forsta v2022 Scripting Manual

GetRespondentUrl("q7","3","2")
will give a link that when opened, will open the survey for the current respondent on the page with q7 for the iteration
with code "3" of l2 and the iteration with code "2" of l1.
In this example,

GetRespondentUrl("alert", true)
will give a link that when opened, will open the survey for the current respondent at the start of the call block named
“alert”. When the respondent finishes the callblock, after submitting the i40 info node, the interview will finish.
In this example,
GetRespondentUrl("q12", false, "alert=true")
will give a link that when opened, will open the survey for the current respondent on the page with q12, passing the
encrypted parameter named alert with a value of “true” (see the UserParameters function for details regarding
accessing the parameter).
In this example,
GetRespondentUrl("", false, "alert=true;state=red")
will give a link that when opened, will start from the beginning of the survey, passing the encrypted parameters named
“alert” and “state” with the values of “true” and “red” (see the UserParameters function for details regarding accessing
the parameter).

Note: When using GetRespondentUrl to pass several text values into the start of the interview, a semicolon ;
is used as a separator. If a ; is required as part of the parameter, it must be encoded.
The plus sign + must also be encoded if used as a parameter.

In this example,
GetRespondentUrl("cb1", true, "alert=true")
will give a link that when opened, will open the survey for the current respondent at the start of the call block named
“cb1”, passing the encrypted parameter named alert with a value of “true” (see the UserParameters function for details
regarding accessing the parameter). When the respondent finishes the callblock, the interview will finish.

Note: When GetRespondentUrl is used to access a callblock, the interview_start, interview_end and interview
status values are not updated during the callblock interviewing session. However, if the callblock contains a
STOP node then interview_end and interview status will be updated.

- 83 -
Forsta v2022 Scripting Manual Forsta Confidential

Important
GetRespondentUrl should not be used to start the interview at a question contained within a callblock as the
interview will fail when the respondent reaches the end of the callblock.

GetRespondentUrl access to a callblock will cause the interview to finish when the callblock is completed. It
is not designed to act as a scripted way to access a callblock.

GetRespondentUrl must not be used with CATI; use GetCatiRespondentUrl (see GetCatiRespondentUrl on
page 119 for more information).

Building a Cryptic URL to be displayed in an info node


Even for the respondents who answer open surveys (for example pop-ups), a unique URL can be used to reenter the
survey.
So if you want respondents to an open survey such as for example a pop-up survey to be able to quit in the middle of
the survey, close their browser and then continue later, they just need to have the correct link with the respondent-
specific parameter. They will then be able to enter their own survey with previous answers intact. Without this link,
they will have to start on a new survey.
To achieve this, one solution is to display the respondent-specific URL in the interview, instructing the respondent to
copy that exact URL if they want to pause and continue later, for example:

In the example above, the survey setting “Encrypt System Request Parameters” is set. If this is disabled, the link will
have r=respid&s=sid instead of __sid__. GetRespondentUrl supports either option for respondent-specific URLs.
You can insert the respondent-specific URL in the text area of an info node as follows:
^GetRespondentUrl()^
The same functions can be used to email a personal link to a respondent (see SendMail on page 150 for more
information).

10.1.3.11. RedirectToRespondentUrl
RedirectToRespondentUrl()
Calling this function will result in an internal redirect to a specific location within the survey. This is similar to
Redirect(GetRespondentUrl()), but without resulting in seeing the new URL.

• If this function is used in an offline survey channel (not Web or CATI), it will be equivalent to calling
Redirect(GetRespondentUrl(…), true).
• The function has the same signature as GetRespondentUrl and all its features (such as redirect to CallBlock
and passing custom parameters) are supported (see GetRespondentUrl on page 82 for more information).
Note that a parameter must be passed. No parameters, that is RedirectToRespondentUrl() on its own, is not
supported.

10.1.3.12. CurrentID
CurrentID()
CurrentID returns the respid of the current respondent. Note that this does not necessarily apply to CAPI interviews;
CurrentID on the CAPI Console returns the CAPI local respondent ID.

Using modulus to route respondents to different parts of the questionnaire

- 84 -
Forsta Confidential Forsta v2022 Scripting Manual

You can use the remainder of respid divided by a number x to route respondents to x different parts of the
questionnaire in rotation. For example, if you have three sections A, B and C, you can create a pattern as:
respondent 1 would complete section B,
respondent 2 would complete section C,
respondent 3 would complete section A,
respondent 4 would complete section B,
respondent 5 would complete section C,
respondent 6 would complete section A,
etc.
This can be done by using the CurrentID() function and modulus / remainder. Depending on the result of
CurrentID()%3
the respondent is routed to the appropriate part of the questionnaire.

See alsoGetResponseID() (see GetResponseId on page 93 for more information).

10.1.3.13. CurrentLang
CurrentLang()
CurrentLang returns the language code of the current language used (e.g. 9 for English). This can be used e.g. in
conditions if you want different routing for different languages. You can also use it to set hidden questions to use in
reporting if you want to report on the different languages.

10.1.3.14. CurrentPID
CurrentPID()
CurrentPID returns the project number of the survey (a number prefixed by p). This can for example be set in a
hidden variable to be used in data exports if you export from several surveys into a common format.

10.1.3.15. CurrentLoops
CurrentLoops()
CurrentLoops is used in validation code, masking and in response piping in a question's text fields (or in functions
called from validation code, masking and response piping) and returns the IDs of all loops that the current question is
located in. Calling CurrentLoops() as a function returns an array of strings containing the loop IDs, with the first (or
outer) loop at the start of the list. It will also return a list with one element in it so it is possible to get the loop ID with
CurrentLoops()[0] or CurrentLoops().ToString().

10.1.3.16. GetRespondentValue and SetRespondentValue


Sometimes you may want to be able to modify values from the respondent list. Through the "background variable"
property in survey questions, values can be fetched from the respondent list and set in the survey data. However you
cannot use these to update the respondent list; it is one-way only.

- 85 -
Forsta v2022 Scripting Manual Forsta Confidential

One scenario where it would be beneficial to update the respondent list is if you have a survey which the respondents
continuously update, and you want to keep sending new reminders to the respondents. If they change their email
address in the survey, you would like the respondent list updated with the new email address so that new reminders
are sent to the new email address.
GetRespondentValue(fieldname)
will return the value uploaded in the fieldname (string) column in the respondent list for the current respondent. If
the fieldname does not exist, null will be returned.
SetRespondentValue(fieldname,value)
will set fieldname (string) in the respondent list to value (string) for the current respondent. If fieldname does not
exist, nothing will happen. There are three system fields that can not be updated: rid, sid and rowguid. Attempting
to update any of these will give a script error.

Calculating the number of days elapsed since a record was uploaded


The following script works out the number of days passed since a record was uploaded in the respondents database.
f('UploadDate').set(GetRespondentValue("CreatedDate"))
//where UploadDate is a date type question

var created = new Date(GetRespondentValue('CreatedDate'));


var d = created.getDate();
var m = created.getMonth() + 1;
var y = created.getFullYear();
var start : DateTime = new DateTime(y,m,d);
var now = new Date();
var end : DateTime = new DateTime(now.getFullYear(), now.getMonth() + 1,
now.getDate());
var span : TimeSpan = end - start;
var days = span.TotalDays;
f('nodays').set(days)

10.1.3.17. InterviewStart, InterviewEnd, SetInterviewStart and SetInterviewEnd


When a respondent opens a Forsta survey, an SQL variable called interview_start is set with the exact time and date.
When the respondent reaches a stop node or the end of the interview, an SQL variable called interview_end is set.
These variables can be used in reporting and are included in data exports. Reporting on time series is for example
based on interview_start.

Note: If a respondent re-enters the interview, interview_start is re-set, and similarly, if she or he reaches a
stop node or the end of the interview after re-entering a completed interview, the variable interview_end is
also re-set.

Two functions can be used to get the values of these timestamps in scripts
InterviewStart()
InterviewStart returns the respondent’s interview start time.
SetInterviewStart(date)
SetInterviewStart sets the respondent’s interview. The parameter date is optional. If it is not included,
interview_start will be set to current server time and date. If date is included, it can either be a JScript.NET
Date object or a .NET DateTime object.
InterviewEnd()
InterviewEnd returns the respondent's interview end time.
We will return to examples on how to use these functions later in the documentation (see InterviewStart and
InterviewEnd on page 188 for more information) where they are used together with the Date object.

- 86 -
Forsta Confidential Forsta v2022 Scripting Manual

There are also two functions available to set these timestamps. SetInterviewStart can be used for example
when you want interview start to be set after the screening questions of a survey instead of at the beginning of the
survey, and SetInterviewEnd can be used to set the interview end timestamp when a stop node is never reached
because of a redirect at the end of the survey (see Redirect on page 156 for more information).
SetInterviewStart() - sets the respondent’s interview start time to current server time and
date.
SetInterviewEnd() - sets the respondent's interview end time to current server time and date.

10.1.3.18. GetStatus and SetStatus


When the respondent reaches a stop node, status is set according to the status defined for that stop node. When the
respondent reaches the end of the interview, status is set to "complete".

Currently Forsta recognizes the following status settings:

Status Code

Complete complete

Screened screened

Quota Full quotafull

Error error

If status is null, it means that the interview is incomplete. The "error" status is set if the interview terminates because
of an error in a script.
There are two functions that operate on status:
GetStatus()
GetStatus returns the current interview status.
SetStatus(status)

- 87 -
Forsta v2022 Scripting Manual Forsta Confidential

SetStatus can be used in a script to set the interview status, e.g. if you want respondents who have answered the
questionnaire up to a certain point to count as complete interviews, even though they do not answer all the remaining
questions. status is a string with the status value you want to set, i.e. "complete", "screened" or "quotafull".
SetStatus is very often used in combination with the Redirect function (see Redirect on page 156 for more
information).
The SetStatus function will just set the interview status, not the interview_end time stamp. interview_end is just set
when the end of the interview or a stop node is reached.

Note: The use of redirects, quotas, status-screened or other solutions with the principle purpose of avoiding
the survey "complete" status being reached by a respondent having offered a reasonable amount of
responses, is prohibited and will be regarded as an attempt to avoid transaction fee obligations to Forsta.

Setting Interview Status Before End of Survey


If you want to set the status of the interview to "complete" before the last questions (which e.g. could be questions
about personal details on where to send incentives etc.), you can include a script node with the following code where
you want the status to be set:
SetStatus("complete");
If you do this, even respondents that do not answer those last questions with personal details will still count as
completes for reporting etc.

10.1.3.19. Forward
Forward()
Forward returns true if the respondent is moving forward through the questionnaire (has clicked on the forward
button), and false if the respondent is moving backward (has clicked on the back button). This can be used for code
that you only want to execute when the respondent moves in a particular direction.
There is no point in using this function in validation code, because validation code is only run when the respondent
moves forward in the questionnaire.

10.1.3.20. IsInRdgMode
IsInRdgMode()
IsInRdgMode returns true if the scripts are executed during a Random Data Generator run, false otherwise. You
may use this function to prevent some script code from being run when testing the surveys with the RDG.

10.1.3.21. SetRandomCategories
SetRandomCategories(number, qid)
SetRandomCategories can be used to randomly switch on the specified number of categories of the specified
question ID. Typically this would be used to randomly turn on number categories of a specific hidden qid. In the
example below, two categories of the hidden question q2 would be switched on.
SetRandomCategories(2, 'q2')
This function is only applicable for standard multi questions. It does not apply to multi questions with the Capture
Order property set.
(see Random on page 195 for more information)

10.1.3.22. TerminateLoop
TerminateLoop()
TerminateLoop is used inside of auto-increment loops. Auto-increment loops are only available for optimized database
projects. A TerminateLoop call is required to stop further iterations of the loop being created. Without this, the loop will
continuously create new loop iterations, and the respondent will never be able to finish the loop.

- 88 -
Forsta Confidential Forsta v2022 Scripting Manual

A script node containing a TerminateLoop function call is a mandatory requirement for an auto-increment loop
because an auto increment loop iteration requires some interactive content for the respondent (question, info node
etc.). If the loop contains nothing interactive, the interview will be terminated with an error status and an error
notification will be sent via email.
Note that the TerminateLoop function call must be placed at the end of the loop to have any effect.
In the following example the loopTermination script node contains the single function call TerminateLoop and is used
to prevent further iterations of the auto-increment loop based on the answer to the "continue" question.

TerminateLoop calls are only applicable to auto-increment loops; they are not applicable to, and have no effect on
loops based on normal answer lists or those based on table lookups.

10.1.3.23. IsAccessibleMode and SetAccessibleMode


IsAccessibleMode()
IsAccessibleMode returns true if the current Survey Layout Theme is a theme in Accessible mode. The function is
useful if you some respondents are responding in accessible mode and some not, and you would like different content
in the two modes.
SetAccessibleMode(bool)
SetAccessibleMode can be used to either set the survey in accessible mode (i.e. switch to a Survey Layout Theme
that is set as Accessible):
SetAccessibleMode(true)
or to set the survey not to be in accessible mode (i.e. switch to a Survey Layout Theme that is not set as Accessible):
SetAccessibleMode(false)

10.1.3.24. UserParameters
UserParameters[paramName]
UserParameters can be used to access texts that are passed to the start of the interview using the
GetRespondentURL() function.
In this example,
UserParameters["alert"]
will give the value that the parameter named “alert” was set to when GetRespondentUrl was used to access the
survey.

Note: UserParameters can only be used on the first page that the respondent is directed to via
GetRespondentUrl. UserParmeters will return empty values if used later in the survey.

To access all parameter information UserParameters.Keys can be used. The Keys function returns a
NameValueCollection which can be iterated through.
In this example, a script function “ShowKeys()” has been created to display all parameter information:

- 89 -
Forsta v2022 Scripting Manual Forsta Confidential

function ShowKeys()
{
var str = "";
for(var x = new Enumerator(UserParameters.Keys); !x.atEnd();
x.moveNext())
{
var y = x.item();
str += "<br />" + y + " = " + UserParameters(y);
}
return str;
}
When piping the result of this function, for example using ^ShowKeys()^ in an interview initiated via
GetRespondentUrl("", false, "alert=true;state=red") the following the following will be displayed:

Note: Survey links in hitlists can have parameters added to the link. Two functions are available to receive the
value from the link; UserParameters and Request (see Request on page 228 for more information). The
function you must use depends on the link's “Link type” setting. UserParameters will only be able to retrieve
the value from the hitlist link when "Link type" in the Hitlist Field Properties page is set to "Encrypted URL
parameters". Refer to the separate Reportal User Guide for further details.

10.1.3.25. GetDeviceInfo
GetDeviceInfo()
GetDeviceInfo() is a scripting function that returns an object containing a variety of information regarding the type of
device that is being used by the respondent.

Note: The information returned is dependent on the rendering modes enabled for the survey. For example, if
mobile rendering channel is not enabled in Survey Settings then IsTablet will return False.

The object returned contains the properties described in the following table:

Property Name Type Value Meaning


IsGeneric Boolean true or false Returns true if the respondent is using a generic mobile
device.
IsDesktop Boolean true or false Returns true if the respondent is using a desktop
device.
IsTouch Boolean true or false Returns true if the respondent is using a touch mobile
phone device, for example an iPhone or Android phone
(not iPad; this returns false - see the Important note
below).
IsTablet Boolean true or false Returns true if the respondent is using a tablet device.
Note that iPad returns false.
IsMobile Boolean true or false Returns true if the respondent is using a mobile device
(phone or tablet). Note that iPad returns false.

- 90 -
Forsta Confidential Forsta v2022 Scripting Manual

ScreenResolution String “600|400” or “0|0” The screen resolution of the device being used
width|height or “0|0” if unknown.
DeviceType String "Desktop", "Touch", The device type in use.
"Generic"
DeviceType.toString() String "Desktop", "Touch", The device type in use.
"Generic"

For example, an info node containing the following:


The results of the function calls are:
GetDeviceInfo().IsDesktop: ^GetDeviceInfo().IsDesktop^
GetDeviceInfo().IsTouch: ^GetDeviceInfo().IsTouch^
GetDeviceInfo().IsTablet: ^GetDeviceInfo().IsTablet^
GetDeviceInfo().IsGeneric: ^GetDeviceInfo().IsGeneric^
GetDeviceInfo().IsMobile: ^GetDeviceInfo().IsMobile^
GetDeviceInfo().ScreenResolution: ^GetDeviceInfo().ScreenResolution^
GetDeviceInfo().DeviceType: ^GetDeviceInfo().DeviceType^
GetDeviceInfo().DeviceType.toString():
^GetDeviceInfo().DeviceType.toString()^
Will return the following information on an iPhone 4:

Note: ScreenResolution will only be available if Smartphone rendering mode is enabled and the device is
either a touch or tablet device.
Note: The definition of "Tablet" is a device with a user agent string conforming to the
UserAgentRegExTouchDevice expression from System Configuration that also has at least one screen
dimension exceeding 650px.

When only Desktop mode is enabled, the screen resolution check is not performed so IsTablet will always return false.

Important
Screen dimension is often considered to be the actual screen resolution that is advertised on a phone’s
specification sheet (i.e. the screen.width and screen.height * the device pixel ratio). If you are using and
relying on the GetDeviceInfo().ScreenResolution information in your survey, be aware that Forsta uses the
viewport’s width and height (that is window.innerWidth and window.innerHeight). Forsta also uses the CSS
Interpretation (the resolution / the device pixel ratio) divided again by the device pixel ratio. These are the
numbers that are returned for GetDeviceInfo().ScreenResolution, and the numbers used to determine tablet.

- 91 -
Forsta v2022 Scripting Manual Forsta Confidential

Important
Be aware that although iPad is classified as a tablet device, iPad is included in the desktop regex (the
UserAgentRegExDesktop expression from System Configuration) that is configured for Forsta. Therefore if a
respondent is taking a survey on an iPad device, IsTablet and IsTouch will never return true; it only gets as
far as the first check (the user agent string) and returns false.

10.1.3.26. GetQuestionIds
GetQuestionIds is used to return a string array of question IDs based on specific filters provided.
GetQuestionIds(questionTypes: String[], variableTypes: String[], loopId:
String)
GetQuestionIds(includeInteractiveQuestions: Boolean,
includeNonInteractiveQuestions: Boolean, loopId: String)
Where:
questionTypes is a string array that filters and lists questions which are of a specific type only. The types
are (case insensitive): "single", "multi", "grid", "ranking", "open text list", "numeric list", "open", "numeric",
"date", "geolocation", "imageupload", "multigrid" and "3dgrid".
variableTypes is a string array which filters and lists questions which are of a variable type, the types are
(case insensitive): "normal", "panelvisible", "hidden", "background", "recoded" and "recoding“.
loopId filters and lists questions inside the specified loop only (not recursive).
includeInteractiveQuestions if set true will filter and list all questions that have normal or panel visible
variable types.
includeNonInteractiveQuestions if set true will filter and list all questions that have hidden,
background, recoded and recoding variable types.
Note that only root nodes of multigrids and 3dgrids are listed. It is possible to get title, text and instruction of a
multigrid or a 3dgrid using f(g1).text() or .label() or .instruction().
In this example,
GetQuestionIds(true, false)
will return a string array of all interactive questions in the survey.
In this example,
var questionsTypesIncluded : String[] = ["open", "numeric"];
f("myQuestions").set(GetQuestionIds(questionsTypesIncluded).toString());
will set the ”myQuestions” answer to be a comma-separated list of all open text and numeric questions in the survey.

10.1.3.27. Get3DGridQuestionIds
Get3DGridQuestionIds is used to return a string array of the questions inside a specific 3DGrid, and will also return
the row question ids of a multigrid when the multigrid id is used as the function argument.
Get3DGridQuestionIds(gridId: String)
Where:
gridId is the question ID of a 3Dgrid.
In this example,
Get3DGridQuestionIds("g1").toString()
will return a comma-separated list of all question IDs inside the 3DGrid “g1”.
As a Multigrid object is a transposed 3D Grid, this function can also be used to retrieve the Question (row) ids of a
multigrid.

Note: When the Multigrid or 3D Grid contains an Other - Specify answer option then the form name will be
returned in the array as the first element.

- 92 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.3.28. GetSurveyPackageVersion
GetSurveyPackageVersion()
The GetSurveyPackageVersion function can be used to return the internal survey package number for the survey
currently being used. This information can be useful when ensuring that a specific version of the survey is being used.

10.1.3.29. GetCompanyId
GetCompanyId()
GetCompanyId can be used to get the ID of the company that this survey belongs to. The CompanyId is an int.

10.1.3.30. GetSurveyName
GetSurveyName()
GetSurveyName can be used to get the name of the current survey, as a string value.

10.1.3.31. GetResponseId
GetResponseId()
This gives the response ID of the current interview record. Use example: The text below could be added to a text field.
The Response ID allocated to this interview is: ^GetResponseId()^
This function can also be used in scripting.
See also CurrentID() (see CurrentID on page 84 for more information).

10.1.3.32. GetLanguageCodes
GetLanguageCodes()
GetLanguageCodes() can be used to return a set of language IDs that exist for the current survey. This can be used
to check if a specific language code/s is valid in a survey, or it can be used as a mask on a question, based on the
available languages. In the example below the function is used to return a set of available languages, then based on
the language codes and the answer codes, the answer list will be filtered to only display the languages available in
this survey.

- 93 -
Forsta v2022 Scripting Manual Forsta Confidential

Figure 1 Example of the GetLanguageCodes function in use

10.1.3.33. FormExists
FormExists(string qid)
FormExists() is used to check if a specific form exists in the current survey. The function returns true if the form exists
in the survey, false if it does not. For example the script below checks if q1 exists:
var qid = "q1";
var questionExists = FormExists(qid);
This can be used in scripting to ensure that a form actually exists, before referencing it.

10.1.4. Browser Information


10.1.4.1. BrowserType, BrowserVersion and trapBrowser
BrowserType()
BrowserType returns the browser type (e.g. "IE" for Internet Explorer), as detected by the MSWC.BrowserType
component.
BrowserVersion()
BrowserVersion returns the browser version (e.g. "6.0"), as detected by the MSWC.BrowserType component.
You can use these two functions to set hidden variables to report on what browser versions your respondents use:

- 94 -
Forsta Confidential Forsta v2022 Scripting Manual

Recording the Respondent's Browser Type and Version


To set browser type and version in the hidden open text questions browsertype and browserversion you can use this
code in a script node:
f("browsertype").set(BrowserType());
f("browserversion").set(BrowserVersion());
trapBrowser can be used to set browser type and browser version as a combined string into a question:
trapBrowser(qID)
qID is the question ID of the opentext question in which the browser type and browser version is to be stored.

10.1.4.2. RequestIP
RequestIP()
Returns the IP address of the respondent as a string on quad IP form. This can for example be used to set the IP
address of a respondent in an open text question.

Note: Recording the respondents' IP addresses may be in conflict with respondents' privacy. Responsibility
for ensuring respondents' privacy resides with the Forsta clients. Forsta recommends following ESOMAR
guidelines, see www.esomar.org.

If you have an open survey, but want to limit the respondents from answering more than once, you might want to
record the IP address and remove responses from repeat IP addresses. However, this probably will not give the
desired effect, because:

• respondents inside a firewall will have the same IP address


• internet providers may use dynamic IP addresses
So to make sure that each respondent answers only once, the best option is to upload a respondent list and email
links with r and s, or to upload username and password and use a login page in the survey.
One useful way of using RequestIP is to use it in combination with the IsNet function to screen respondents from a
particular domain (see IsNet on page 150 for more information).

10.1.5. Ranking Questions and Capture Order Multis


The functions described in this section can be used on ranking questions and multi questions with the "Capture Order”
property set. These questions will, for each answer list item, store an integer which represents the rank it was given
(for example ranked as number 1) or in which order it was selected (selected 1st). A few functions are provided to
easily retrieve the element that was selected first etc.

Note: The Capture Order property is only available in surveys using the Optimized database.

- 95 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.5.1. First
This function is used to return the first category selected for multi choice questions with the capture order property, or
the category ranked as 1st for a ranking question.
First(qid)
First returns the code or label, depending on the context, of the first selected or ranked as number 1 answer category
for the specified question ID qid. Label will be returned in text piping mode (within ^s), code elsewhere.
This function can only be used on ranking questions and multi's that have the capture order property enabled. It is not
applicable to other multis.

If these responses were given in the order ITV1, BBC1, Channel 5, we would get the following result from using
First():

- 96 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.5.2. Nth
This function returns the nth category selected for a multi choice question with the capture order property, or the
category ranked as the nth for a ranking question.
Nth(qid,position)
Nth returns the code or label, depending on the context, of the answer category in the position specified for the
specified question ID. Label will be returned in text piping mode (within ^s), code elsewhere.
Nth(“q1”,1) will return the same value as First(“q1”). This function can only be used on ranking questions or multi's that
have the capture order property enabled. It is not applicable to other multis.

If these responses were given in the order ITV1, BBC1, Channel 5, we would get the following result by using Nth():

- 97 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.5.3. AnswerOrder
This function is used to return an array of codes in the order selected for a multi choice question, or in the order
ranked for a ranking question.
AnswerOrder(qid)
AnswerOrder returns the codes of the answers supplied in the order they were selected or ranked for the specified
question ID. The primary purpose of this function is to make it easy for users to retrieve the selected answer codes
without having to use the Nth() function and loop through the answer list multiple times, which would result in poor
script and server performance in the event of a very long answer list.
This function can only be used on ranking questions or multi's that have the capture order property enabled, it is not
applicable to other multis.

10.1.5.4. Setting Variables for Nth Mentioned / Ranked for Reporting Purposes
If you have a ranking question or a capture order multi, you will easily be able to report on which ranks/order of
mention each answer got. However, if you want to report on answers per rank/order of mention, you will save some
recoding work by creating a set of hidden single variables for each rank/order of mention, that have the same answer
list as the multi.
In this example we have a question “cars”, in which the respondents are asked to rank up to three of their favorite
cars. The three hidden single questions rank1, rank2 and rank3, are set up with the same answer list as the multi, and
will be used to store the car selected as number 1, 2 and 3.

The following script will set the single questions based on the responses to the ranking question:
var ordered = AnswerOrder("cars");
for(var i=0;i<ordered.length;i++)
{
f("rank"+(i+1)).set(ordered[i]);
}

10.1.6. Table Lookup Specific Functions


10.1.6.1. GetDBColumnValue
This is a survey engine scripting function used to retrieve data from an additional column or columns associated with a
specific table inside of a table lookup list.
GetDBColumnValue(schemaID, tableID, keyID, additionalColumnName,
[languageID])
where:

- 98 -
Forsta Confidential Forsta v2022 Scripting Manual

schemaID is the ID of the schema in database designer.


tableID is the ID of the table.
keyID (string) is the ID of the value being searched on (ID row from the contents of the table).
additionalColumnName is the name of the column that the data is to be pulled from.
[languageID] is the ID of the language to be retrieved from. This is optional; if not specified it uses the
respondent's language for this survey.

Note: The schema and table IDs being referenced must be part of the survey, either as an answer list or loop
list. If a table is referenced that is not used in the survey, the function will fail at run-time.

This function can be used to retrieve values from additional columns that are associated with answers for a table
lookup list defined within database designer. For example a table lookup list may be defined in the following way:
The database schema “Basic_Cars” (schema ID 805) contains table “car_list” (table ID 1543) with a list of
cars, each containing their own unique string key value. Additionally there are 2 columns “cost” and “spec”
containing background information relating to the specific cars.

During the survey, the author would like to pipe in the answer to “cost” and store the value of “spec” in a hidden
question. If table lookup question named car_owned is based on this table lookup as follows:

Piping in the value of the cost of the selected car can be achieved using the following syntax:
^GetDBColumnValue(805, 1543, f('car_owned').get(), 'cost')^
as shown here:

- 99 -
Forsta v2022 Scripting Manual Forsta Confidential

Similarly, if the value for spec for the English language (language ID is 9) is to be stored in the hidden question
c_spec, the following script syntax can be used:
f('c_spec').set(GetDBColumnValue(805, 1543, f('car_owned').get(), 'spec',
9))
If the keyID value is supplied explicitly, this must be contained within quotes as this is a string value. For example, to
store the value of keyed 7, the following syntax can be used:
f('c_spec').set(GetDBColumnValue(805, 1543, '7', 'spec', 9))

Note: The GetDBColumnValue() function is not executed during a Random Data Generator run. In this case
the value returned will be empty.
Note: The GetAdditionalColumnValue method is described here (see GetAdditionalColumnValue on page 46
for more information).

10.1.7. Offline Mobile App Specific Functions - CAPI and AskMe App
CAPI (Computer-Assisted Personal Interviewing) and AskMe App (Self-Completion) are Forsta add-ons.
CAPI App is designed for face-to-face interviewer led survey intercepts using Android, iOS or Windows devices.
AskMe App is designed for self-complete where the respondent completes the surveys on their own personal device.
Supported platforms are Android and iOS.
For more information on specific platform support for CAPI and AskMe App, refer to the Forsta System Requirements
document on Forsta.com

Note: The JavaScript Survey Engine must be enabled to use these functions. To enable this, check the "Use
JavaScript scripting engine" survey setting.

10.1.7.1. CAPI and AskMe App Shared Functions


The functions described under this function apply to both CAPI and the AskMe App.

10.1.7.1.1. GetDeviceUniqueId
Return the unique ID for the device being used. Note that the identifier is retained/persisted even if the app is
uninstalled.
GetDeviceUniqueId()
Alternatively, see GetOfflineInfo() for related information.

10.1.7.1.2. GetOfflineInfo
Use GetOfflineInfo() function, to access app and device information:

• AppVersion returns the application version in use.


• BatteryLevel returns the battery level in the device.
• DeviceLanguage returns the language code as exposed by the operating system (e.g. "fr").

- 100 -
Forsta Confidential Forsta v2022 Scripting Manual

• DeviceLanguageId returns the Forsta language code determined by the device locale (e.g. fr-be = 2060
French Belgium). Note that this is the derived Forsta language code and may not be the language set for a
survey if the survey does not contain the same language. To determine if the survey contains the same
language, you are recommended to use CurrentLang() to determine if the target device language is supported
by the current survey.
• DeviceLocale returns the device country code exposed by the operating system (e.g. "be").
• DeviceModel - returns the model information exposed by the operating system.
• DeviceOs returns the operating system the device is using.
• DeviceOsVersion returns the operating system version.
• DeviceUniqueId returns the device's unique id code.
• DeviceName returns the name of the device (if exposed by the operating system).
Examples of use:
var lvl = GetOfflineInfo().AppVersion
var lvl = GetOfflineInfo().DeviceOs
var lvl = GetOfflineInfo().DeviceOsVersion
var lvl = GetOfflineInfo().BatteryLevel
var lvl = GetOfflineInfo().DeviceModel
var lvl = GetOfflineInfo().DeviceUniqueId
var lvl = GetOfflineInfo().DeviceName

10.1.7.1.3. GetSurveyDeviceVariable, SetSurveyDeviceVariable, GetUserDeviceVariable and


SetUserDeviceVariable
AskMe and the CAPI app support the ability to write to and read from local storage on the device, either in the scope
of the current survey, or the same user. These functions allow data to be stored within the app for future reference,
which can be very useful for preventing re-asking questions or for building workflows between respondents/interviews
or surveys. To access this information there are four scripting functions:
SetSurveyDeviceVariable()
GetSurveyDeviceVariable()
SetUserDeviceVariable()
GetUserDeviceVariable()
SetUserDeviceVariable is scoped to the same user but can share between surveys. This can be used for example, to
store information relevant to the currently logged in CAPI interviewer.
SetSurveyDeviceVariable scope is local to the same survey only, shared between respondents. This can be used for
example, to track a counter for every completed survey in AskMe.
To clear a device variable, set the value to null. Example:
SetSurveyDeviceVariable("diaryIteration", null);
GetUserDeviceVariable and GetSurveyDeviceVariable will return null if key is not found.

Example usage
Here we are setting/getting a counter for the survey local variable (just referencing the value of QID q1):
SetSurveyDeviceVariable("diaryIteration", f('q1'));
GetSurveyDeviceVariable('diaryIteration')
And here we are setting/getting the user's name from a user-level local variable (just referencing the value of QID
fullname):
SetUserDeviceVariable("AskMeUsername", f('fullName'));
GetUserDeviceVariable('AskMeUsername')

- 101 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.7.1.4. Background Audio Capture


AskMe and CAPI provide the ability to record audio responses (see the separate Survey Designer User Guide for
more information on adding these question types). However, there may be situations where you would like to record
for longer durations, or record while the interview continues. For these situations a script method to trigger when to
start and end an audio recording is available. A survey can contain more than one audio capture question, allowing
audio recording throughout a survey, possibly covering multiple sections throughout an interview.

Note: You cannot set the value for an Audio Capture question.

startAudioCapture
Starts the audio recording.
f(qID).startAudioCapture()
Where qID is an audio capture question contained anywhere within the survey (it is recommend to set this as hidden).

Note: If this is the first time audio recordings have been initiated by the application on the device, the user
may be prompted to allow access to the microphone. This could be confusing to the user as it may not be
obvious why this is being requested. It may therefore be advantageous to include an Information node to
explain what is happening and why.

stopAudioCapture
Stops the audio recording.
f(qID).stopAudioCapture()
The audio recording will be saved to the audio capture question referenced by qID.
Note that the following conditions will also cause the recording to be stopped:

• If the survey is closed (postponed, canceled, etc).


• If another audio recording is initiated either via startAudioCapture or a visible audio (or video) capture
question.
• When the Max property set for the audio capture question (qID) has been reached.

Note: You cannot set the value for an Audio Capture question, and the Min property will be ignored.

10.1.7.1.5. openVideoInApp
Function to play a video using the device built-in video player triggered by a button or other event:
openVideoInApp()
Example question text HTML source:
<a onclick="openVideoInApp('/isa/BDJPDAVIOEQJR/p5165/demo.mp4');return
false;">Play Video</a>
Alternatively, videos can be presented using the <video> HTML tag:
<video playsinline width="100%" controls preload="none">
<source src="/isa/BDJPDAVIOEQJR/p5165/demo.mp4" type="video/mp4" />
</video>
Video files can be added to the File Library making them available for offline viewing.
Device specific behavior for playsinline option (e.g. within same survey view):

• iPhone: always plays fullscreen regardless (inline not supported)


• iPad: plays inline
• Android (phone or tablet): plays inline if playsinline property provided.

- 102 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.7.1.6. openAudioinApp
This function plays an audio file:
openAudioInApp(url,openExternalPlayer)
where:

• url is the file library path to the audio file.


• openExternalPlayer is a boolean value. Setting to true (default) plays the audio file using the default built-in
audio player on the device. Setting to false will play the audio directly in the app without any controls. This can
be helpful for playing short audio clips where controls are not needed.
Example question text HTML source:
<a onclick="openAudioInApp('/isa/BDJPDAVIOEQJR/p5165/demo.mp3');return
false;">Play Audio</a>
Alternatively, audio can be presented using the <audio> HTML tag:
<audio playsinline width="100%" controls preload="none">
<source src="/isa/BDJPDAVIOEQJR/p5165/demo.mp3" type="audio/mpeg />
</audio>
Audio files can be added to the File Library, making them available for offline playback.

10.1.7.2. CAPI App Specific Functions


The functions described under this section are specific the CAPI App.

10.1.7.2.1. PostponeInterview
PostponeInterview(“description”, removeOnSync)
This function can be used to postpone a survey automatically when an interviewer reaches a specific point in the
survey path and the interview is to be considered as postponed. In CAPI App this function is equivalent to the
interviewer going to the in-survey menu and selecting Postpone Interview.
The description parameter is optional; if it is not supplied, the following default text will be recorded – "Interview
postponed via script".
The removeOnSync parameter is an optional boolean value (default false). If it is supplied, the description parameter
is required. The removeOnSync parameter will result in the survey being removed on the next sync that is performed.
This provides a way to allow respondents to be completed across many different CAPI devices or even web. For
example, in the situation where a survey needs to be started on Device A, postponed, re-assigned to Device B,
postponed, re-assigned back to Device A, the latest respondent will not be downloaded on Device A in normal
situations as the respondent on Device A is retained after being uploaded. By setting removeOnSync to true, this will
allow the respondent on Device A to be removed allowing a new/updated respondent to be downloaded at a later
time.

10.1.7.2.2. GetCapiInterviewerName
GetCapiInterviewerName()
GetCapiInterviewerName returns the username of the currently logged on interviewer.

10.1.7.2.3. GetCapiDeviceOs
GetCapiDeviceOs()
GetCapiDeviceOs() returns the operating system used by the device. The returned string values can be:
Windows
Android
iOS
If the device is not set up for CAPI, then nothing is returned.
Alernatively, see GetOfflineInfo() for related information.

- 103 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.7.2.4. GetCapiBatteryLevel
GetCapiBatteryLevel()
GetCapiBatteryLevel() returns the current percentage level for the CAPI device battery as a numeric value. This
function only applies to Android and iOS CAPI apps; the Windows CAPI console, and any other modes such as a
CATI or web survey, will always return a value of 100.
Alernatively, see GetOfflineInfo() for related information.

10.1.7.3. CapiAssignRespondent
CapiAssignRespondent(“interviewername”)

This function can be used to allow CAPI assignments to be added to the current respondent, meaning this interview
will then be available for the CAPI interviewer to work on in the CAPI channel.
If the CAPI channel is not enabled for the survey, or if an invalid CAPI interviewer name is provided, the survey will
continue and the survey author will receive an error email.
If the record is already assigned to another interviewer, calling this function will replace the existing assignment with
the new assignment.

Note: This function is intended to be initiated while running in CAWI to facilitate transition of an online survey
to an offline survey in CAPI.

10.1.7.4. CapiUnassignRespondent
CapiUnassignRespondent()

This function can be used to remove an interviewer assignment from this respondent.
If the CAPI channel is not enabled for the survey, the survey will continue and the survey author will receive an error
email.

Note: This function is intended to be initiated while running in CAWI to facilitate transition of an online survey
to an offline survey in CAPI.

10.1.7.5. AskMe App Specific Functions


The functions described under this section are specific to the AskMe App. Refer to the separate Survey Designer user
guide for further information on the AskMe app.

10.1.7.5.1. GetOfflineSurveyDescription and SetOfflineSurveyDescription


The AskMe app has the ability to control the description text that appears for surveys in survey tiles - see the figure
below. You can also read from and write to that description using the functions:

- 104 -
Forsta Confidential Forsta v2022 Scripting Manual

GetOfflineSurveyDescription()
SetOfflineSurveyDescription(description)

The rules for this text are:

• The text defaults to the survey description input in Survey Designer.


• HTML formatting is supported. However, hyperlinks are not supported.
• If a respondent data field called “SurveyDescription” exists, the text will take the value of this variable. This
allows for respondent-level overrides of the initial value for the field.
• The function SetOfflineSurveyDescription() can be used to set the text while the survey is being completed.
Refer to the separate Survey Designer user guide for further information on the AskMe app.

10.1.7.5.2. Survey Reminders


Survey Reminders allow survey authors to script the display of one-time and recurring notifications that display in the
device notification area to remind them to complete a survey. This is useful for diary studies, for example, where a
survey author may want a reminder to be set for a time in the future when the app can remind the user to complete
the next iteration of the survey. Depending on the type of study, the frequency of when to prompt the user can vary
significantly. In some cases, it may require multiple surveys per day, and different times of the day for each
respondent. In other cases it may be some time far into the future, for example a month or more.
This set of functions facilitates this alarm functionality.
Note that there are some limitations regarding the device OS:

- 105 -
Forsta v2022 Scripting Manual Forsta Confidential

• The number of iOS concurrent notifications is limited due to a limitation in the OS. It may be possible to
schedule up to 64, but this number may be significantly lower depending on the surveys that are loaded in the
app.
• Major device or OS upgrades may discard set alarms.

SetSurveyNotification
SetSurveyNotification(reminderName, displayLabel, notificationTimestamp)

• reminderName (String) - Unique identifier for this alarm


• displayLabel (String) - Text to display in notification. Plain text only. Recommended max length: 70
• notificationTimestamp (Date) - Date and time when to display notification. Max value < 60 days in future
This function sets a one-time reminder to display at a specific time in the future. This reminder will display regardless
of whether the app is in use or not. Tapping on the reminder notification starts the app and enters the survey inside
which the call was made.
Calling the function with the same reminderName overwrites previous settings.
Example: Remind user at the same time tomorrow
// Gets the current date and time
var date = new Date();
// Adds 24 hours to the date
date.setHours(date.getHours() + 24);
SetSurveyNotification("tomorrow", "Please record your diary input now.",
date);
Example: Remind on the 12, 14, 16th of the current month
// create 3 separate reminders
// Gets the current date and time
var reminder1 = new Date();
// Sets the date to the 12th of the month
reminder1.setDate(12);
// Gets the current date and time
var reminder2 = new Date();
// Sets the date to the 14th of the month
reminder2.setDate(14);

// Gets the current date and time


var reminder3 = new Date();
// Sets the date to the 16th of the month
reminder3.setDate(16);

SetSurveyNotification("MonReminder", "Please record your diary now.",


reminder1 );
SetSurveyNotification("WedReminder", "Please record your diary now.",
reminder2 );
SetSurveyNotification("FriReminder", "Please record your diary now.",
reminder3 );

SetAppNotification
SetAppNotification(reminderName, displayLabel, notificationTimestamp)

• reminderName (String) - Unique identifier for this alarm


• displayLabel (String) - Text to display in notification. Plain text only. Recommended max length: 70
• notificationTimestamp (Date) - Date and time when to display notification. Max value < 60 days in future
This function sets a single-shot reminder to display at a specific time in the future. This reminder will display
regardless of whether the app is in the foreground or background. Tapping on the reminder notification starts the app.

- 106 -
Forsta Confidential Forsta v2022 Scripting Manual

In contrast to SetSurveyNotifications, this does not start a specific survey. This allows for situations where the user
may need to continue where they left off providing an opportunity to resume.
Calling the function with the same reminderName overwrites previous settings.

SetRepeatingSurveyNotification
SetRepeatingSurveyNotification(reminderId, displayLabel, minuteOfHour,
hourOfDay, dayOfWeek)

• reminderName (String) - Unique identifier for this alarm


• displayLabel (String) - Text to display in notification. Plain text only. Recommended max length: 70
• minuteOfHour (Number) - The minute for the hour to trigger (0-59)
• hourOfDay (Number) - The hour of the day to trigger (0-23)
• dayOfWeek (String, optional) - Day of the week labels (mon, tue, wed, thu, fri, sat, sun)
This function sets a recurring reminder. This reminder will display regardless of whether the app is in the foreground
or background. Tapping on the reminder notification starts the app and enters the survey inside which the call was
made.
The firing of this notification is based on the minuteOfHour, hourOfDay and dayOfWeek settings. At every time where
there is a match of these values with the current time, the notification will fire. For example, if we desire the notification
to fire every Monday at 9am, we would set minuteOfHour to 0, hourOfday to 9 and dayOfWeek to "mon".
The dayOfWeek parameter is optional. If not provided, the reminder will recur every day.
Calling the function with the same reminderId overwrites previous settings.
Example: Remind every day for next 3 days at 10am
SetRepeatingSurveyNotification("10amReminder", "Please record your daily
diary now.", 0, 10);
// NOTE: survey multiple complete set to Max 3 which will stop alarms
once 3 surveys are completed
Example: Remind every week on Saturday mornings
SetRepeatingSurveyNotification("SatReminder", "Please let us know your
weekly activities.", 0, 10, "sat");

CancelSurveyNotification
CancelSurveyNotification(reminderId)

• reminderName (String) - Unique identifier for this alarm


This function cancels the notification associated with reminderId.

CancelSurveyNotifications
CancelSurveyNotifications()
This function cancels all notifications set in this survey.

GetLastSurveyNotificationDate
GetLastSurveyNotificationDate()
This function returns the timestamp of the last time a notification was displayed to the user from this survey based on
the set notifications.
It is important to understand that this returns the expected last notification timestamp, not the timestamp of the last
actual display of a notification.
Example: Provide time window for when survey can be completed

- 107 -
Forsta v2022 Scripting Manual Forsta Confidential

// ensure the user started the survey within 15 minutes of receiving the
survey reminder
var d = new Date();
d.setMinutes(d.getMinutes() - 15);
if( GetLastSurveyNotificationDate() < d )
{
//show an informational question - "Sorry, you didn't start the survey in
time. You will get another chance tomorrow"
}
Example: Check if user has notifications enabled for app
if(!IsAppNotificationPermissionEnabled())
{
// Show informational node to ask user to enable notifications

IsAppNotificationEnabled
IsAppNotificationEnabled()
This function checks if the user has enabled notification permissions for the app.

ShowAppNotificationSettingsDialog
ShowAppNotificationSettingsDialog()
This function displays the notification permissions screen to allow the user to change the setting for the app.

10.1.7.5.3. GetAdvertisingInfo
Use GetOfflineInfo().GetAdvertisingInfo() function, to access device Advertising information:

• .AdvertisingID returns the device advertisingID where possible. This is a helper function without needing to
perform platform specific checks.
• .GAID returns the Google Advertising ID (Android only, iOS returns null).
• .IFV returns the Apple Identifer for Vendors (iOS only, Android returns null).
• .IFA returns the Apple Identifer for Advertisers (iOS only, Android returns null).
• .IsLimitAdTrackingEnabled returns true if user has enabled option to limit ad tracking (Android only, iOS
returns null).
• .IsAdvertisingTrackingEnabled returns true if user has enabled option to limit ad tracking (iOS only, Android
returns null).

Examples of use:
var adId = GetOfflineInfo().GetAdvertisingInfo().AdvertisingID
var gaid = GetOfflineInfo().GetAdvertisingInfo().GAID
var ifv = GetOfflineInfo().GetAdvertisingInfo().IFV
var ifa = GetOfflineInfo().GetAdvertisingInfo().IFA
var isl = GetOfflineInfo().GetAdvertisingInfo().IsLimitAdTrackingEnabled
var isl =
GetOfflineInfo().GetAdvertisingInfo().IsAdvertisingTrackingEnabled

10.1.7.5.4. notifyNativeApp
This function is available for custom branded AskMe applications.
notifyNativeApp(provider, eventName, customData)

10.1.8. CATI Specific Functions


CATI (Computer-Assisted Telephone Interviewing) is a Forsta add-on.

- 108 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.8.1. Redo
Redo() forces a redo of a specific question:
Redo('qid')
where qid is the question ID of the question that is to be re-done.
Redo can be used together with SetErrorMessage to provide a redo-context sensitive error message (this can be
defined per language). Example:
Redo(‘q1’)
SetErrorMessage(LangIDs.en, 'Error Message')
Considerations regarding use of Redo:

• Redo can only be used for surveys that use the optimized database format.
• Redo can only be used in CATI, CAPI or AskMe survey channels. If, however, a survey is running in the CATI
channel then Redo is available for CAWI interviewing also. No error will be reported at launch time if the
survey contains an 'unsupported' Redo , instead the survey will produce an internal error at runtime.
• The question id has to be a question that the interviewer has seen before (i.e. a question that has already
been processed).
• The question id can be a question inside a callblock. If the callblock has been called multiple times, the the
most recent call the callblock will be chosen.
• The question id can be a question inside a loop. The first iteration of the loop is chosen.
• The function is supported by quick test.
Invoking the Redo() will cause the engine to return to the specified question ID. Having then answered this question
the engine will fast forward back to the script that invoked the Redo. If during fast forward the interview cannot
progress due to a change in the interview path or due to some validation the interview will continue from that point.

Important
When fast forwarding through the project, the Redo() WILL be re-executed. Therefore an example such as:
q1 - Gender question
Script: Redo('q1')
will produce a loop, repeating q1 over and over again. This is intentional behavior. It is the survey author's
responsibility to use the function in a way that takes this into account. The Redo is intended to be based on a
particular condition that must be resolved to bypass the Redo, so it will typically be placed within a condition
or similar.

10.1.8.2. GetTelephoneNumber and SetTelephoneNumber


Two functions exist for dealing with the telephone number of the respondent in CATI surveys. This can either be to
access the value of the respondent's telephone number, or to explicitly set the value of the respondent's telephone
number. The telephone number is a special field that is displayed in the survey's call list in CATI supervisor as well as
on the manual selection screen for interviewers.
GetTelephoneNumber()
will return the value of the current respondent's telephone number (string).
An example of retrieving the value of the respondent's telephone number may be as part of an initial contact screen,
such as the infomation node below:

- 109 -
Forsta v2022 Scripting Manual Forsta Confidential

This would be represented as follows in the CATI interviewing Console:

Similarly the telephone number can be set inside a script node in Survey Designer as follows:
SetTelephoneNumber(value)
Where value is the (string) value that is to be assigned as the respondent's telephone number.

10.1.8.3. GetExtensionNumber and SetExtensionNumber


Two functions exist for dealing with the telephone number extension of the respondent in CATI surveys. This can
either be to access the value of the respondent's telephone number extension, or to explicitly set the value of the
respondent's telephone number extension.
GetExtensionNumber()
will return the value of the current respondent's telephone number (string).

- 110 -
Forsta Confidential Forsta v2022 Scripting Manual

An example of retrieving the value of the respondent's telephone number extension may be as part of an initial contact
screen, such as the info node below:

This would be represented as follows in the CATI interviewing Console:

Similarly the telephone number extension can be set inside a script node inSurvey Designer as follows:
SetExtensionNumber(value)
Where value is the (string) value that is to be assigned as the respondent's telephone number extension.

- 111 -
Forsta v2022 Scripting Manual Forsta Confidential

Note: On a supporting dialer the system field for ‘ExtensionNumber’ will be sent to the dialer as a call
property to specify the desired Caller ID (CLID). This means that individual CLIDs can be set by supplying the
desired values in a sample file (using a column headed ‘ExtensionNumber’). Contact support to check if your
system supports this functionality.

10.1.8.4. GetTimeZoneId and SetTimeZoneId


Two functions exist for dealing with the time zone that the respondent resides in CATI surveys. It is possible to either
retrieve or set a value for the respondent’s time zone. The time zone associated with the respondent corresponds to
the time zone list from the resources tab inside of the CATI supervisor. An example list is as follows:

The first ‘ID’ column corresponds to the respondent's time zone Id.
GetTimeZoneId()
will return the numeric Id stored for the current respondent.
It is also possible to define the time zone for the respondent; this can be achieved using a script node. Here
SetTimeZoneId(value)
can be used to set the value of the time zone, where value is an valid integer time zone Id value. In the following
example the respondent's time zone is changed to time zone Id 3 (GMT+1).

- 112 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.8.5. GetExtendedStatus and SetExtendedStatus


The Extended Status is the status primarily used for CATI interviewing that stores the call outcome of the interview
record. The extended status is a numeric value corresponding to the extended status list within the CATI Supervisor.
An example list is shown below:

GetExtendedStatus()
will return the value of the current interview's extended status value (integer). If no value is set 0 will be returned.
A typical example of where this may be used is in the End block of a CATI interview. When an interviewer terminates
the interview during an interview, the interview is immediately given a GetExtendedStatus() value of 6. The End block
can then be used to react to this termination. In the example below, for interview terminations the type of termination
is sub-classified by a termination question and then the interview is further dispositioned to a new extended status
value depending on the termination type:

It is also possible to define the extended status value for an interview. This can be achieved using a script node. Here,
SetExtendedStatus(value)
can be used to set the value of the extended status, where 'value' is a valid integer extended status value; an integer
between 1 and 120.
The initial contact screen that is used to record the call-outcome of the call demonstrates the use of this function. Here
we can see the Dial_Outcome question where the call-outcome is recorded:

- 113 -
Forsta v2022 Scripting Manual Forsta Confidential

This contains the following answer list:

The codes here correspond to the extended status code list within the CATI supervisor. Therefore the script node s1
is used to disposition the interview with a SetExtendedStatus() value corresponding to the code for the selected
category in the Dial_Outcome question.

10.1.8.6. GetLastInterviewStart
GetLastInterviewStart()
GetLastInterviewStart returns the date/time of the previous call attempt made to this respondent.

10.1.8.7. GetLastChannelId
GetLastChannelId()
GetLastChannelId returns the ID (integer) corresponding to the channel used during the last interview attempt

ID Channel
0 None
1 Web
2 CAPI
4 Random Data
Generator
8 CATI

10.1.8.8. GetCatiInterviewerId
GetCatiInterviewerId()
GetCatiInterviewerId returns the ID corresponding to the CATI interviewer as defined by the ID column in the CATI
interviewer list in the CATI supervisor.

- 114 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.8.9. GetCallAttemptCount
GetCallAttemptCount()
The GetCallAttemptCount function is used to return the number call attempts made to this respondent. For example
the following info node would display the number of attempts made:

This function is for CATI only, not CAPI.

10.1.8.10. GetTotalAttempts
GetTotalAttempts()
The GetTotalAttempts function is used to return the number of attempts made to this respondent in either CATI or
Web interview modes. For example,
^GetTotalAttempts()^
used in an info node would display the total number of attempts made to this respondent in either CATI or Web
interviewing.

Note: This function is not available for CAPI interviewing and is only available for surveys that have the CATI
channel enabled.

10.1.8.11. GetDialMode, SetDialMode and GetDialingMode


Three functions exist for dealing with the dial mode in use when a company has the CATI Telephony add on enabled.
GetDialMode checks the respondent data value, and SetDialMode explicitly sets the value of the dial mode.
GetDialingMode gets the "live" in-progress dial mode assigned to this call in the dialer.
GetDialMode()
and
GetDialingMode()
will return a numeric value corresponding to the list below.
1 = Manual
2 = Preview
3 = Automatic
4 = Predictive (requires the additional predictive telephony add on)
The dial mode can be set inside a script node in Survey Designer as follows:
SetDialMode(value)
Where value is either 1, 2, 3 or 4 based on the list above.

10.1.8.12. GetDialStatus
A function exists that returns the outcome of a dial attempt made by the dialer (when a company has the CATI
telephony add on enabled). The GetDialStatus() function call will return a numeric value corresponding to the outcome
list below.

- 115 -
Forsta v2022 Scripting Manual Forsta Confidential

Dial status value Description


0 Connected call
2 Busy
3 No reply
7 Answer phone
8 Modem
9 Fax
10 Congestion
11 Unobtainable
12 Nuisance
15 Returned not dialed
25 Returned dialer expired
28 Stopped
29 Telephony failure
30 Error

Typically this would then be used to control either continuing the call or finishing the interview, as shown in the
screens below:

With the script doing the following:

- 116 -
Forsta Confidential Forsta v2022 Scripting Manual

Note: The GetDialStatus() function should not be called before the dial command has been issued for this
interview. If it is, it will return the last DialStatus value from the previous call, or a “0” if it is the first call. For
surveys using more than 1 dial mode (for example a predictively dialed survey that has preview in predictive
calls), ensure that appropriate logic surrounds the function such that it is only retrieved once the dial
command has been issued.

10.1.8.13. GetDialType
GetDialType()
GetDialType() can be used to obtain information about how the current phone interview was dialed, either manually
(by hand) or automatically (using an autodialer).

10.1.8.14. GetTotalDuration
GetTotalDuration()
The GetTotalDuration function is used to return the number of seconds spent interviewing cumulatively across all
interview attempts. For example the follow info node would display the amount of time spent on this interview across
all interview attempts:

10.1.8.15. GetCatiInterviewerName
GetCatiInterviewerName()

- 117 -
Forsta v2022 Scripting Manual Forsta Confidential

GetCatiInterviewerName returns the username of the currently logged on interviewer. This is the Login column in
the CATI interviewer list in the CATI supervisor. This is typically used during the initial greeting with the respondent,
for example as follows:

10.1.8.16. GetCatiAppointmentTime
GetCatiAppointmentTime()
GetCatiAppointmentTime returns the time (in local respondent time) for the CATI appointment that has just been
made. This is designed to be used in the Exit block at the end of the current interview only. For example the following
survey would display the time and also capture it to a hidden variable to be used at the start of a subsequent call. An
example of such a survey is:

Where the captureAppointmentTime script contains the following:

This is then piped in during the Start block in the i3 info node.

- 118 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.8.17. GetCatiRespondentUrl
This is GetRespondentUrl for CATI.
Using a redirect inside a CATI survey that jumps to a specific question in the survey (for example
Redirect(GetRespondentUrl("q1")) results in the interview continuing in Web mode with a number of negative
implications because GetRespondentUrl is not supported in CATI. The GetCatiRespondentUrl() function has the same
signatures as GetRespondentUrl() and is intended for use in CATI interviewing to safely jump to a specific question.
The same rules apply as for GetRespondentUrl() (see GetRespondentUrl on page 82 for more information).

Note: The GetCatiRespondentUrl() function must ONLY be used in conjunction with redirects to questions
inside of the same CATI survey. The GetCatiRespondentUrl() function only applies in the CATI interviewing
mode. If it is used in other modes it behaves like GetRespodnentUrl().

10.1.8.18. GetCatiStationId
GetCatiStationId()
GetCatiStationId() can be used to obtain the CATI interviewer station ID of the device being used to conduct the
current interview. Each workstation in a CATI call center has its own workstation label (Station ID) – specified as a
string when making a fresh console installation.

10.1.8.19. StartVoiceRecording and StopVoiceRecording


StartVoiceRecording('label')
StartVoiceRecording is only applicable when connected to a supported Forsta Local Dialer. When issued inside
of a script node, sectional voice recording will begin. This will continue to run until a StopVoiceRecording() function
call is made or the interview finishes. The user-supplied text label passed is incorporated into the filename of the .wav
sound file created.
StopVoiceRecording(stopRecordingMode: String)
Where:
stopRecordingMode is an optional parameter that can either be "WholeInterview", "Sectional" or "Both".
StopVoiceRecording is only applicable when connected to a supported Forsta Local Dialer. When issued inside of
a script node, if voice recording is enabled for this interview then the specified voice recording type will be stopped on
the dialer. If no value is supplied, the default is “Both”.
Depending on which dialler is being used, different recording methods are available:

1. TCI and ProTS: whole interview recording and sectional recording are available. However it is not possible to
have concurrent whole interview recording and sectional recording; if whole interview recording is enabled
when a StartVoiceRecording() function call is made the whole interview recording will be stopped
2. Open Dialler API diallers: whole interview recording and sectional recording are available, even concurrently.
Whole interview recording cannot be controlled with scripting functions – for example
StopVoiceRecording(‘WholeInterview’) or StopVoiceRecording(‘Both’) - unless ‘Enable whole interview audio
recording’ is checked in Survey Designer > Survey Settings > CATI - Telephone.
If only sectional recording is required, ‘Enable whole interview audio recording’ must be unchecked.

10.1.8.20. fr
fr()

Note: This function is obsolete; you should use GetRespondentValue() instead (see GetRespondentValue and
SetRespondentValue on page 85 for more information).

This function is only available in survey scheduling within the CATI supervisor. The function can be used to reference
the value of CATI replicated background variables in a scheduling script. Only variables with the "Available as CATI
filter" question-level property can be referenced. The following demonstrates how a filter can be used when referring
to the value of the CATI replicated variable named gender:

- 119 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.8.21. IsCallExpired
IsCallExpired()
This function is only available inside of survey scheduling inside of the CATI supervisor. CATI scheduling is invoked
when a call expired event occurs. Typically, this would be due to an appointment expiry timeout being reached. During
scheduling execution the IsCallExpired function returns true if scheduling has been invoked due to a call expiry event.
This allows a new call to be scheduled in this scenario, here the actions are to remove assignment locking, set the call
priority to be 2000 and set the time to call to be now.

10.1.8.22. AddToCatiBlacklist
AddToCatiBlacklist()
This function is available in Survey Designer for CATI-enabled projects. When this function is called, the current
respondent’s telephone number (contained within the respondent data variable named TelephoneNumber) will be
added to the company's telephone blacklist. The telephone blacklist can be managed from the CATI Supervisor, from
the Resources tab > Telephone Blacklist item. When telephone blacklist support is enabled at the survey level in
Survey Designer, any attempt to call one of the blacklisted numbers will not be processed and the respondent
extended status will automatically be changed to 'Blacklist'. Duplicate numbers or numbers containing spaces or
special characters such as ( ) + # - will not be added to the list. Refer to the separate CATI Supervisor User Guide for
further information on creating and maintaining a telephone blacklist.

10.1.8.23. GetParamValue
GetParamValue(value)
This function is only available in survey scheduling in the CATI supervisor. If the scheduling script contains some
defined parameters then these parameters can be referenced in filters in scheduling. In this example a scheduling
parameter named TimeFrame exists, where ID is 1.

- 120 -
Forsta Confidential Forsta v2022 Scripting Manual

To refer to these parameters, use the GetParamValue(value) function where you can either pass the
GetParamValue("ParameterName") or GetParamValue(ParameterId) to reference by name or ID. For example,
GetParamValue(“TimeFrame”) or GetParamValue(1). The example below shows this being used in the filter for the
Busy call outcomes.

10.1.8.24. StartCATIAudioPlayback
StartCatiAudioPlayback (“filename”,[auto_start])
This function is only applicable for CATI-enabled projects, in the CATI channel and when working with a supported
Dialer. When this function is called a command is sent to the dialer to play the specified sound file. The function can
be used in any interactive text that will be displayed to the CATI interviewer; typically this would be a question relating
to the sound file being played. This function should not be used inside of non-interactive nodes such as script nodes
or hidden questions as this will result in nothing being played to the CATI interviewer.
The parameters are the filename (excluding path) of the .WAV file to be played and optionally a Boolean for
automatically starting the sound file playback when the function is invoked. The auto_start parameter determines
whether the sound file should immediately start playing when the function is invoked, if this is not specified the default
value is false (or 0) meaning the file will not start playing immediately. Example of usage is as follows:

In this example, the CATI interviewer console will activate the sound playback buttons on this page allowing the CATI
interviewer to play, pause or stop the sound clip, “radio1.wav”, it will not start automatically. Using this syntax:
^StartCatiAudioPlayback("radio1.wav", 1)^ upon displaying this page the sound file would immediately be played.
A CATI interviewer can use the play, pause and stop toolbar buttons to control the playback of the audio file and
whenever the audio file is playing both the interviewer and the respondent will hear it. These buttons are only active
for questions that make use of the sound playback capabilities. Sound file playback will automatically be stopped if the
CATI interviewer submits the current page.

Note: It is the responsibility of the survey author or the person who manages the local dialer to ensure that
the sound file has been placed in the appropriate directory on the dialer(s). This task is not automated in any
way by the Forsta system. If the file cannot be located and played by the dialer the interview will continue as
if the there was no request to play a sound file.

10.1.8.25. IsInOpenendReviewMode
IsInOpenendReviewMode()

- 121 -
Forsta v2022 Scripting Manual Forsta Confidential

This function is only applicable for CATI-enabled projects, being interviewed in the CATI channel.
IsInOpenendReviewMode returns true if the function is executed during CATI openend reviewing, false otherwise.
You may use this function to prevent questions from appearing during openend reviewing either as part of a question
mask or from condition logic. This would typically be used for open text questions that do not require review at the end
of the CATI interview.

Note: If you use this masking, remember to check the "No cleaning on question masking" property (refer to
the separate Survey Designer user guide for more information). If this property is not checked, then the data
will be cleared if the page is empty.

10.1.8.26. AddRespondentToCati
AddRespondentToCati(extendedStatus)
This function is only applicable for CATI-enabled projects, and applies to interviews being conducted in the Web
interviewing mode. It is designed for open surveys where respondent data has not been loaded into the system and
the Web respondent needs to continue the survey in the CATI interviewing channel. When this function is called the
current respondent will be initialized in the CATI system and be available to be interviewed on in the CATI interviewing
channel. If a record already exists for that respondent ID in the CATI interviewing channel the existing respondent will
be updated and have the specified extended status value allocated to it.
The extendedStatus parameter that is supplied is the numeric value of the extended status (between 1 and 120) that
will be assigned to the respondent in the CATI system; call scheduling will be executed on this call using this extended
status value.
The following example demonstrates how this could be used in an open Web survey:

If the answer to the question in “transferToCati” is “Yes” (code 1) then the respondent name and telephone number is
collected and initialized via the script node “initializeCati”. The call is then initialized in the CATI interviewing channel
with an extended status value of 21 (“Transfer to CATI”). The script contains the following code:
SetRespondentValue("respondentname", f("respName"));
SetTelephoneNumber(f("telNumber"));
AddRespondentToCati(21);

Note: You must ensure that a scheduling rule is defined to handle calls with the specified extended status to
ensure that an appropriate CATI call is created.

10.1.8.27. CreateCatiAppointment
CreateCatiAppointment()
This function is available for CATI-enabled projects in Survey Designer. When this function is called, the appointment
dialog will appear on the CATI interviewing console. The interviewer will be able to make an appointment and on
clicking OK the survey will finish with an appointment status. If the interviewer clicks Cancel, they will be allowed to
continue the interview without making an appointment.

Note: This function is only effective if there is an interactive question located after it in the survey. If there are
no interactive questions in the survey after this function is called then the function will be ignored, the
appointment dialog will not appear and the interview will merely continue until it is finished.

- 122 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.8.28. CreateCustomAppointment
This function can be used when CAWI respondents would like to set up an appointment to be called back via CATI.
The CreateCustomAppointment function can be used in a CATI schedule custom script to create an appointment for
CATI using date and time information captured from survey variables.
The function 'CreateCustomAppointment' will accept parameters for date/time in the respondents time zone.
Example:
function CreateAppointment()
{ var time: DateTime = DateTime.Parse('2021-01-25 13:00');
CreateCustomAppointment(time); }
Refer to the CATI Admin manual for a worked example

10.1.8.29. EnableLiveMonitoring and StartScreenRecording


Legislation in some countries prohibits live monitoring of respondent's answers until they provide their explicit consent
for such live monitoring. To comply with these rules the Forsta software provides means of disabling and enabling the
interview live monitoring and video recording functions. Two controls which make it possible to only enable live call
monitoring and/or video recording of the interviewers screen if the respondent has given explicit consent are activated
by settings in the survey's Survey Settings > CATI Options tab (refer to the separate Survey Designer user guide for
further details).

Figure 2 The Monitoring and recording options in the CATI Options tab

When the second option for either of these settings is selected, the call monitoring and/or video recording features will
only be permitted after explicit consent has been obtained in the survey. This requires that the survey includes the
corresponding script functions:
EnableLiveMonitoring()
StartScreenRecording()
A simple method of achieving this is to add the functions to a script node inside a condition that is activated by a
"Yes/No" consent question. No parameters are required for the functions.

Figure 3 The functions in a script node in the survey

- 123 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.8.30. IsCatiGroupMember
IsCatiGroupMember()
The IsCatiGroupMember function can be used to check if the interviewing agent conducting the current interview
belongs to a given group (as specified by the function by referring to it with its applicable group name). The function
returns FALSE if the interviewer is not a member of the specified group.

Figure 4 Example of usage

10.1.8.31. IsCatiIvr
IsCatiIvr()
Use the IsCatiIvr function to determine if the current interview is operating in IVR mode. If this is the case then the
function will return true.

10.1.8.32. IsCatiInbound
IsCatiInbound()
Use the IsCatiInbound function to determine if the current interview was initialized via an inbound call to the call
center. If this is the case then the function will return true.

10.1.8.33. Linked Surveys / Interviews


The following set of functions can be used to facilitate linkages across different surveys and interview records. A
common use case is when handling inbound calls and where there is a need to locate an applicable survey and
interview record for the respondent. Initially the interviewer is put into a locating survey where they obtain relevant
locating details from the respondent before being able to transfer to the appropriate survey/interview from a resulting
lookup table.

10.1.8.33.1. GetCatiInterviews
GetCatiInterviews can be used to find other interview records, for example it can be used in an inbound call scenario
to locate a pre-existing interview record when CLI matching is not possible and so a new temporary interview has
been created.
GetCatiInterviews(string[] surveyList, string telephoneNumber, string
respondentName, string filter)
Both telephoneNumber and respondentName parameters work as a “starts with” filter. So if “1234” is specified as a
telephoneNumber, it will search for all numbers starting with “1234”.
These parameters also support wildcards:

• % - Any string of zero or more characters.


• _ (underscore) - Any single character.
So if “%1234” is specified as a telephoneNumber, the system will search for all numbers containing “1234”. The filter
parameter makes it possible to search interviews by survey questions (only those that have the “Available as CATI
filter” option enabled). Its format is:
“q2=2 AND q3=1”

- 124 -
Forsta Confidential Forsta v2022 Scripting Manual

It does not support wildcards and must always be an exact match.


In the typical Inbound interview locating scenario, the function returns an array of objects which should be placed into
an open text list variable. Then in turn a single type variable is used to show the results contained in the open text list
so that the user is able to select a specific record. After the interviewer selects an applicable single response answer,
it is necessary to parse the open text list item string to get the project id and resp id.

10.1.8.33.2. SetNextCatiInterview / SetNextCatiInterviewToPrevious


SetNextCatiInterview()
SetNextCatiInterviewToPrevious()
These functions do not immediately switch interview, but just set the next interview to start after finishing the current
interview. SetNextCatiInterview determines which survey and interview record to start.
SetNextCatiInterviewToPrevious returns interviewing activity back to the previous survey record.

10.1.8.33.3. GetCatiLinkedInterviews
GetCatiLinkedInterviews()
This returns a list of “parent” interview records. This is a list of previously started interviews in the current linked
interviews chain (where the SetNextCatiInterview function has been used).

10.1.8.34. Writing Custom CATI Script Code


In the event you wish the scheduling script to perform operations which cannot be configured using the regular CATI
Supervisor functions available through the user interface, you can write the script code manually. This requires a
thorough knowledge of the JavaScript.NET language.
The script code you enter using this tab is executed only when the “Run specified script” action is enabled.
To create a custom scheduling script manually:

1. With the scheduling script opened in the View mode, go to the Custom Script tab in the lower-right frame.

This tab contains a single text field, which you use to enter your script code.

2. Enter the script code (JavaScript.NET language is used) in the text field. You can also paste the clipboard
contents into this field. Click the Parse button in the lower-right frame's toolbar to check the code is correct.
(see Accessing the Call Object in Custom Scripting on page 125 for more information).

10.1.8.34.1. Accessing the Call Object in Custom Scripting


This topic describes how the call object can be accessed in custom scripting, inside of CATI scheduling. This
functionality is available through the "Scheduling" object which is available in custom scripts. The "Scheduling" object
has the following properties:

Type Name Description

- 125 -
Forsta v2022 Scripting Manual Forsta Confidential

BvSurveyEntity Survey This object provides


data for the survey
which contains the
current interview.
ReadOnly.
BvInterviewEntity Interview This object provides
data for interview which
is scheduled.
Read/Write.
BvCallEntity LastCall If the scheduling script
is run for interview
which previously had a
call, then this object
contains info about the
call, otherwise null.
ReadOnly.
BvCallEntity NewCall If the scheduling script
creates a call, this
object provides info
about the new call. If
the object is null, call
will not be created upon
scheduling completion.
Read/Write.
DateTime Time Scheduling time.
ShiftService Shifts This object provides for
shift functionality.

A function exists to initialize a new call inside of the scheduling object when used via a custom scheduling script:
CallShouldBeCreated()
Once initialized Scheduling.NewCall will be initialized and available.
To cancel the creation of the new call, set Scheduling.NewCall to Null.
Object breakdown
BvSurveyEntity object provides access to survey data as follows:

Type Name Description


Int SID Internal object ID
String Name Project ID
String Description Project name
Int ScheduleID Scheduling script ID

BvInterviewEntity object provides access to interview data as follows:

Type Name Description


Int ID ID of interview
String TelephoneNumber Respondent telephone number
String RespondentName Respondent name

- 126 -
Forsta Confidential Forsta v2022 Scripting Manual

Int TimezoneID ID of respondent timezone


Int TransientState Extendend status
DateTime LastCallTime Last call time
Int LastCallPersonSID User ID of last interview
byte DialingMode Dialing mode

BvCallEntity object provides access to call data as follows:

Type Name
int CallID
int SurveySID
int InterviewID
int Phase
int RoleID
int ShiftID
DateTime TimeInShift
DateTime TimeToExpire
int Priority
int Resource
int ApptID
int ResourceType
Guid RuleNumber

Shift functionality is available through the ShiftService object supporting methods when working with shifts:

• MatchingShift GetExactShift(DateTime utcNowTime, int tzID)


• MatchingShift GetMatchingShift(DateTime utcTime, int tzID)
• DateTime GetMatchingTime(DateTime utcNowTime, int tzID)
• MatchingShift GetNextShift(MatchingShift currentShift, int tzID)
• MatchingShift GetNextShift(MatchingShift currentShift, int tzID, out int countSkipShifts)
• MatchingShift GetNextShiftByID(DateTime utcTime, int tzID, int scriptShiftID)
• MatchingShift GetNextShiftOfSpecifiedType(DateTime utcTime, int tzID, int scriptShiftTypeID)
• MatchingShift GetShiftAfterNumberOfMinutes(DateTime utcNowTime, int tzID, int countMinutes)
• MatchingShift GetShiftAfterNumberOfShifts(DateTime utcNowTime, int tzID, int numberOfShifts)
• MatchingShift GetShiftAfterNumberOfShifts(MatchingShift curentShift, int tzID, int numberOfShifts, bool
isTakingExclusionIntoAccount)
Custom code examples

1. Custom script creates new call with priority 10


function ScriptFunction()
{
CallShouldBeCreated();
Scheduling.NewCall.Priority = 10;
}

- 127 -
Forsta v2022 Scripting Manual Forsta Confidential

2. Custom script creates new call with priority which is taken from number variable with 'num_prior' name
function ScriptFunction()
{
CallShouldBeCreated();
Scheduling.NewCall.Priority = f("num_prior").get();
}

3. Custom script creates new call with time to call on next shift
function ScriptFunction()
{
CallShouldBeCreated();
var shift = Scheduling.Shifts.GetMatchingShift( Scheduling.Time,
1/*Timezone*/ );
shift = Scheduling.Shifts.GetNextShift( shift, 1/*Timezone*/ );
Scheduling.NewCall.ShiftID = shift.ShiftTypeID;
Scheduling.NewCall.TimeInShift = shift.StartDate;
}

4. Custom script creates new call and assigns the interviewer with the ID from variable ‘inter’
function ScriptFunction()
{
CallShouldBeCreated();
var name = f("inter").get();
Scheduling.NewCall.Resource = PersonRepository.GetByName( name ).SID;
}

5. Custom script writes the interviewer's SID to variable 'history' (for all interviewers who have conducted an
interview)
function ScriptFunction()
{
var history= f("history").get();
var name : String = "";
if( Scheduling.Interview.LastCallPersonSID != 0 )
{
var person =
PersonRepository.GetByID(Scheduling.Interview.LastCallPersonSID);
if( person != null )
{
if( String.InNullOrEmpty(history))
history = person.name;
else if( !String.Split( history, ',' ).Any( x => x == person.name ) )
history = history + "," + person.name;
else
return;
f("history").setValue(history);
}
}
}

10.1.9. Multimode Functions - CAWI to CAPI


The functions listed under this section are intended to be initiated while running in CAWI to facilitate transition of an
online survey to an offline survey in CAPI.

10.1.9.1. CapiAssignRespondent
CapiAssignRespondent(“interviewername”)

- 128 -
Forsta Confidential Forsta v2022 Scripting Manual

This function can be used to allow CAPI assignments to be added to the current respondent, meaning this interview
will then be available for the CAPI interviewer to work on in the CAPI channel.
If the CAPI channel is not enabled for the survey, or if an invalid CAPI interviewer name is provided, the survey will
continue and the survey author will receive an error email.
If the record is already assigned to another interviewer, calling this function will replace the existing assignment with
the new assignment.

Note: This function is intended to be initiated while running in CAWI to facilitate transition of an online survey
to an offline survey in CAPI.

10.1.9.2. CapiUnassignRespondent
CapiUnassignRespondent()

This function can be used to remove an interviewer assignment from this respondent.
If the CAPI channel is not enabled for the survey, the survey will continue and the survey author will receive an error
email.

Note: This function is intended to be initiated while running in CAWI to facilitate transition of an online survey
to an offline survey in CAPI.

10.1.10. Chart
10.1.10.1. ChartTotal
ChartTotal(chartID)
ChartTotal returns the current total number of responses in the question the chart with the id chartID is based on. The
function is typically used in conditions to prevent showing the chart until a minimum number of responses is reached.

10.1.11. Quota
Note: The functions described in this section are not supported by CAPI.

- 129 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.11.1. qf
The function qf is used to check if a quota is full.
qf(quotaName)
qf will check if the quota quotaName is full with the current respondent's answers on the questions the quota is
based on, and will return true if it is full and false if it is not.
If the respondent qualifies for several quotas within quotaName, qf returns true if one of these is full, and false if
none of them are full. If Optimistic Quota is enabled on quotaName then the In Progress counts are considered by the
qf() function.

Note: The use of redirects, quotas, status-screened or other solutions with the principle purpose of avoiding
the survey "complete" status being reached by a respondent having offered a reasonable amount of
responses, is prohibited and will be regarded as an attempt to avoid transaction fee obligations to Forsta.

Quota Check
If a quota genderQuota is based on a question gender, and the quota is full for males and not full for females,
qf("genderQuota")
will return true if the respondent has answered "Male" on the gender question, and false if the respondent has
answered "Female" on the gender question.

Presetting a Quota Question to Check Several Quotas


Note: This example has been superseded by the GetLeastFilledQuotaCodes() function (see
GetLeastFilledQuotaCodes on page 131 for more information). You should consider using this function
instead of the example given here as it is more efficient.

Sometimes you have quotas based on a brand list, where the respondent may qualify for several of the quotas, but
you want to pick only one of the brands the respondent has chosen and ask a set of questions for that brand only. Out
of the brands the respondent has chosen, there should be picked a brand where the quota is not full yet. To check
this, we have to try to set the quota question and use qf to check the quota until we find a brand where the quota is
not full.
Let us say there is a multi question brands, and from this question one of the brands answered should be picked, if
the quota is not full for that brand. We set up a hidden single question chosen_brand that should hold this brand. The
quotas will be set up based on this question in the quota brandsquota.
The script will try to set chosen_brand to a brand chosen in brands, check the quota and continue to next brand if the
quota is full. If the quota is not full, the current brand will be used.
var answers = f("brands").categories(); //codes of all brands selected
for(var i : int = 0;i<answers.length;i++) //iterate through the codes
{
var code = answers[i]; //current code
f("chosen_brand").set(code); //try to preset this code
if(!qf("brandsquota")) //check if quota is not full for this code
{
break; //if quota is not full, keep this brand
}
}

- 130 -
Forsta Confidential Forsta v2022 Scripting Manual

After this script chosen_brand will either be set to a brand where the quota is not full, or if the quota is full for all the
brands chosen_brand will be set to the last one. Typically the interview should terminate if the quotas are full for all
the brands answered, so after the script there should be a normal quota check in a condition, and then an info and a
stop node with quotafull status in the then-branch. The expression in the condition should be like this:
qf("brandsquota")

10.1.11.2. qc and qt
The function qt is used to retrieve the target set for a particular quota, and qc is used to retrieve the current count.
qt(quotaName)
qc(quotaName)
qt and qc both return an integer. They will return target and count for the quota cell in the quota quotaName
corresponding with the current respondent's answers on the questions the quota is based on.
If the respondent qualifies for several quotas within quotaName, qt and qc will return -1.

Note: Quota functions require a database, so will not work in Quick Test / External Quick Test.

Allocate a Respondent to the Lowest Current Quota Cell


Assume for example that you are performing a survey to evaluate respondents’ feelings about five different web page
layouts, but you want each respondent to only evaluate one of the layouts. You also want the respondents to be
evenly distributed across the five layouts. You could use the following script to select which layout a respondent is
shown:
var form = f('q1')
var codes = form.domainValues();
var count = 2000; //a value higher than your highest quota target

var code;
var lowestCode;

/*Loops through all the alternatives in q1 and checks whether the quota
count is lowest with that answer*/

for(var i: int=0; i<codes.length; i++) {


__var code = codes[i];
__form.set(code);
__if( qc("quota1") < count ) {
____count = qc("quota1");
____lowestCode = code;
__}
}

form.set(lowestCode);
Here "q1" is the question id for the question with an answer per web page layout tested (should normally be a hidden
question). "quota1" is the quota id for the quota used in the survey. Now you can create skip logic in the survey based
on q1.

Note: It is important that the quota ‘quota1’ does not have any quota cells set to 'Any' for this example. If that
is the case then the respondent will qualify for several quota cells, and the qc() function will then return -1
which will stop the script working as required.
If the Total rows or columns of the quota have been changed manually in quota Grid View, then an 'Any' row
may be added to the table automatically. The respondent will then always qualify for both one of the answer
choices AND the Any cell, hence resulting in -1 being returned by these functions.

10.1.11.3. GetLeastFilledQuotaCodes
The function GetLeastFilledQuotaCodes is used to retrieve an ordered array of codes for the least filled quota cells for
a specific quota.

- 131 -
Forsta v2022 Scripting Manual Forsta Confidential

GetLeastFilledQuotaCodes(quotaName, N, [code mask])


where
quotaName is the name of the quota to be evaluated.
N is the number of quota cell codes to be returned if available.
[code mask] is an optional array that can be applied as a mask when considering the quota cells.
The array returned is the codes of the quota cells ordered by least filled first, in percentage terms. If the percentage
filled values are equal, then the equal cells are ordered randomly. The function can be used with a quota which is
based on one question only, the question can be either a single or multi choice question, but there cannot be more
than one question used in the quota. If the quota is based on more than 1 question an empty array is returned.

Note: In quick test mode, external test mode and through RDG, this function returns an empty array. See
below.

For testing purposes you can create your script so that the GetLeastFilledQuotaCodes() function is only called when
in production mode, and script another way to select quota cells for any of the test modes. For example:
if(IsInProductionMode())
{
f("top_5_cars").set(new Array(GetLeastFilledQuotaCodes('quota1',
5,f("cars_driven").categories())));
}
else
{
SetRandomCategories(5,"top_5_cars"); //test mode so select 5 random
quota cells
}
For a quota based on multi choice question, answers code(s) without the prefix questionName_ are returned. Quota
cells that are already full or that have a target value of 0 are not returned. For a quota based on a single choice
question, [Any] cells are not considered and are not retuned by the function. For a quota based on a multi choice
question all answers should be [Any] except one which should be [Chosen]; only cells with this structure are
considered by the function.
In this example:

There is an interactive multi choice question “cars_driven”, a hidden single choice question “car” and a hidden multi
choice question “top_5_cars” has the same answer list. Of the cars selected in “cars_driven” the quota cell that is
least filled is assigned to the question “car”, and the top five least filled quota cells are assigned to the question
“top_5_cars”. This is achieved using the “assignValues” script node, the contents of this is:
//Find the least filled quota cell and assign it

- 132 -
Forsta Confidential Forsta v2022 Scripting Manual

f("car").set(GetLeastFilledQuotaCodes('quota1',
1,f("cars_driven").categories()).toString());
//Find the top 5 least filled quota cells and assign them
f("top_5_cars").set(new Array(GetLeastFilledQuotaCodes('quota1', 5,
f("cars_driven").categories())));
The loop “l1” is then masked based on the value assigned to the question “car”, meaning that only the chosen car
(least filled quota) will have the loops questions asked.
Note that the ...(new Array()... is required because Forsta returns a standard .NET array type but "Array" in
JScript.NET is different; this then eliminates any possible incompatibility.
Other examples of using this function include:

1. Display the least filled code:


^GetLeastFilledQuotaCodes('quota1', 1).toString()^

2. Display the length of the array:


^GetLeastFilledQuotaCodes('quota1', 6).Length^

3. Display the top 3 filtered by a hard-coded array:


^GetLeastFilledQuotaCodes('quota1', 3, ['1', '2', '3', '4', '5',
'6']).toString()^

Note: The GetLeastFilledQuotaCodes() function is calculated every time the function is called, therefore if it is
executed several times in the same interview, the values returned could be different due to either the state of
the quotas changing or due to the random selection of cells that are equally full in percentage terms.
Note: This function does not take into account the Optimistic Quota setting. I.e. in an Optimistic Quota the
returned array is ordered based on the percentage of Counter/Target and does not include the In Progress or
Optimistic Total Limit.

If Optimistic Quota is enabled on a quota that is used with GetLeastFilledQuotaCodes(), then potentially the function
could return quota cell codes where interviews are In Progress and therefore quota cells could overachieve their
targets if the In Progress interviews complete. By using qf() and GetLeastFilledQuotaCodes() it is possible to check if
the least filled cells are already optimistically full. Below is an example script:
var qtaId = "aQuotaId"; //a quota that has Optimistic Quota enabled
(there is no additional advantage in using this script unless Optimistic
Quota is enabled)
var qid = "qtaQuestion"; //the question on which the quota is based
var n = 99; //this should be the number of cells defined in
the quota
var openCells = GetLeastFilledQuotaCodes(qtaId,n);
var leastFilled;
var stop = false;
if(openCells.length>0)
{
var leastFilled = openCells[0];
for(var i=0; !stop && i<openCells.length; i++)
{
var currCell = openCells[i];
f(qid).set(currCell);
if(qf(qtaId))
{
//optimistically, In Progress interviews might fill this cell soon,
discount it
f(qid).set(null);
}
else
{
//this cell is included in Least Fill and also isn't optimistically full,
let's use it and stop the for() loop:

- 133 -
Forsta v2022 Scripting Manual Forsta Confidential

stop = true;
}
}
if(!f(qid).toBoolean())
{
//all quota cells are OPTIMISTICALLY full, maybe redirect the interview
to some quota full handling call block?
}
}
else
{
//all quota cells have achieved targets, redirect the interview to some
quota full handling call block
}

10.1.12. Credits in Panels


This section describes the functions that can be used to give points (credits) to panelists. Some functions can be used
only in Standard Panels and Professional Panels, and some can also be used in Basic Panels. Basic Panels and
Standard Panels and Professional Panels are Forsta add-ons. If you do not have access to this functionality, please
contact your Forsta account manager for more information.

10.1.12.1. SetPanelistCredit
SetPanelistCredit is used for giving panelists points for registering in the panel and responding to surveys.
SetPanelistCredit can be used in Basic Panels, Standard Panels and Professional Panels.
SetPanelistCredit(credit, comment)
SetPanelistCredit(credit, comment, sectionId)
SetPanelistCredit(credit, comment, panelistId)
SetPanelistCredit(credit, comment, panelistId, sectionId)
All of these update a global credit counter in the panel called CreditBalance which can be found inside the
PanelistParticipation folder. The instance of the function that is being used, depends on the number of parameters
and their type.
credit is an integer that represents the number of points that is to be added to the balance. comment is a String that
can be used to include some information about why the points were added. The limit for comment is 256 characters.
If you include just credit and comment as parameters, you set credit points to be added to the credit balance from
the survey the panelist is responding to. These points will be added as soon as interview status is set to "complete",
"screened" or "incomplete" for the respondent. A repeated call to the function in the same survey will overwrite the
previous credit assigned for the survey.
If you would like to assign different sets of points for different parts of a survey, you can also include sectionId.
sectionId is a String with maximum 40 characters that can identify different parts of the survey. You can call the
sections whatever you like as long as you are within the 40 character limit and do not use Unicode characters. The
credits (points) will be active as soon as the respondent's interview status is set. If the panelist does not have any
status (=incomplete), a pending flag will be set and the points will not become active until the status changes to for
example "complete", "screened" or "quotafull".
If you need to update points for a different panelist, you can do this by including the panelistId (integer) of that
panelist. This can for example be done to credit panelist's that refer friends to the panel. You may send the panelistid
(respid in panelist survey) of the panelist that referred into the survey in the URL and retrieve it with Request(see
QueryString on page 228 for more information), and then use SetPanelistCredit to credit his/her points balance.

Note: Panelistid must be a valid number/integer. If panelistid is a String, then the current panelist will be used
irrespective of the panelistid value.

SetPanelistCredit() can over-write an existing row depending on how the function is called. The full function call,
including all arguments is:
SetPanelistCredit(credit, comment, panelistId, sectionId)

- 134 -
Forsta Confidential Forsta v2022 Scripting Manual

Credit and comment are required arguments. If you wish to make more than one set from a “single survey record”,
you will also need to include the sectionId.
Example: Assuming a starting credit value of 5000, run the following script for a specific record in the survey:
SetPanelistCredit(-1000,'redemption')
At this point you will have a balance of 4000. If you change the script to the following and re-launch and re-enter:
SetPanelistCredit(-2000,'redemption')
on viewing the balance you will see 3000, not the expected 2000. If you wish to have each expression counted
“separately”, you must add a sectionId. This will cause separate rows to be written for each. For example:
SetPanelistCredit(-1000, 'redemption','R-20130827170301')
In the example, a sectionID of "R-" is specified and then YYYYMMDDHHMMSS is appended. This is pulled from a
new Date() object. You can alter your code to send in a sectionID that will be different each time a panelist runs over
the script. This ensures that a new row will be written.

Note: If you just want something unique per row, use .getTime() from a new Date() object.
Note: comment is limited to 256 characters and sectionId is limited to 40 characters.

Also note that rows are marked 'pending' until a status (complete, screened, etc ) is set for the record.

10.1.12.2. Using Custom Variables with SetPanelistCredit


Custom Variables variables are supported in Standard and Professional Panels.
SetPanelistCreditWithCustomVariables(credit, comment, fieldNames,
fieldValues)
SetPanelistCreditWithCustomVariables(credit, comment, sectionId,
fieldNames, fieldValues)
SetPanelistCreditWithCustomVariables(credit, comment, panelistId,
fieldNames, fieldValues)
fieldNames (array of Strings) are the names of the custom fields in the credit transaction loop in the database to be
updated, and fieldValues are the corresponding values to set in these fields.

10.1.12.3. GetPanelistCreditBalance
GetPanelistCreditBalance()can be used to retrieve the credit balance for a panelist as an integer. You can get
either the total balance or the balance within a specific period. GetPanelistCreditBalance is supported in Basic Panels,
Standard Panels and Professional Panels.
GetPanelistCreditBalance()
returns the current total for a panelist as an integer.
With the Date Time parameters fromDate and toDate you can get the balance for a panelist within a specific period
as an integer (the sum of all the transactions within that period), e.g:
GetPanelistCreditBalance(fromDate, toDate);

Displaying Current Credit Balance in a Survey


If you want to show the panelist their current credit balance in a survey, you can include the following in the text of an
info node or question:
^GetPanelistCreditBalance()^

Calculating Credit Balance for the Last 30 Days


The following function can be used to calculate the credit balance, looking at the last 30 days ("adding" -30 days).

- 135 -
Forsta v2022 Scripting Manual Forsta Confidential

function last30()
{
var toDate : DateTime = DateTime.Now;
var fromDate : DateTime = toDate.AddDays(-30);

return GetPanelistCreditBalance(fromDate,toDate);
}

10.1.12.4. GetPanelistCredits
The GetPanelistCredits function can be used to retrieve a subset of a panelist's transactions, as an array of
PanelistCredits objects. GetPanelistCredits is supported in Basic Panels, Standard Panels and
Professional Panels.
GetPanelistCredits(topN);
GetPanelistCredits(fromDate,toDate);
GetPanelistCredits(topN, fromDate, toDate, startPosition,
orderAscending);
GetPanelistCredits(topN) will return an array of PanelistCredits objects (see below), representing the last topN
transactions. topN is an integer.
GetPanelistCredits(fromDate,toDate) will return an array of PanelistCredits objects (see below),
representing transactions performed between fromDate and toDate. fromDate and toDate are both of type
DateTime.
GetPanelistCredits(topN,fromDate,toDate,startPosition,orderAscending) will return an array of
PanelistCredits objects (see below), representing the first topN transactions performed between fromDate and
toDate, if ordered ascending (true for orderAscending) or descending (false for orderAscending). topN is an
integer, fromDate and toDate are both of type DateTime and orderAscending is Boolean.
The PanelistCredits objects in the array returned have the following properties:
pCredit.CreditId
CreditID (integer) is the unique identifier for a transaction.
pCredit.PanelistId
PanelistID (integer) is the responseid of the panelist the credits are assigned to.
pCredit. SecondaryPanelistId
SecondaryPanelistId (integer) is the responseid of another panelist. This field holds a different panelistid if points
have been set from a different panelist’s survey (for example for referrals).
pCredit.PanelistTransactionId
PanelistTransactionId (integer) is the id of the transaction, unique to this panelist.
pCredit.SectionId
SectionId (String) is an identifier a survey designer may assign to the credits, for example if assigning credits to
panelist at various points in the survey.
pCredit.SurveyId
SurveyID (String) is the project number (pXXXXXX) of the project the credits were assigned from.
pCredit.Credit
Credit (integer) is the number of credits (points) assigned to the panelist in this transaction. A negative number
would represent points withdrawn.
pCredit.Comment
Comment (String) is a text assigned to the transaction, for example explaining what the transaction represents.
pCredit.Created
Created (DateTime) is the time the transaction was made (added).

- 136 -
Forsta Confidential Forsta v2022 Scripting Manual

pCredit.Pending
Pending (Boolean) represents whether the transaction is pending (not active) or not. If the transaction is pending, the
flag is set to true, if not, it is set to false.

Retrieving and Listing the last 10 Panelist Credits Transactions inside a Survey
The following functions will list out the date, project number and credits (points) of the last 10 credits transactions
assigned to the current panelist in an HTML table:
function ShowCredits()
{
_var pCredits = GetPanelistCredits(10);
_var txt = "<table>\n"
_txt += "<tr><td>Date</td><td>Project</td><td>Points</td></tr>\n";
_for(var i : int = 0;i<pCredits.length;i++)
_{
__txt+="<tr><td>"+pCredits[i].Created+"</td>";
__txt+="<td>"+pCredits[i].SurveyId+"</td>";
__txt+="<td>"+pCredits[i].Credit+"</td></tr>\n";
_}
_txt += "</table>\n";
_return txt;
}

10.1.12.5. Using Custom Variables when Getting Panelist Credits


Custom variables are supported in Standard and Professional Panels.
GetPanelistCreditsWithCustomVariables(topN, fieldNames);
GetPanelistCreditsWithCustomVariables(fromDate,toDate, fieldNames);
will retrieve panelist credit transactions with the default properties (see GetPanelistCredits on page 136 for more
information) and in addition any custom variables listed in fieldNames (array of Strings), either the topN first records or
the records between fromDate and toDate.

Retrieving and Listing the last 10 Panelist Credits Transactions inside a Survey,
including custom variables
The following functions will list out the date, project number, credits (points) and the two custom variables listed in the
array fieldNames, of the last 10 credit transactions assigned to the current panelist in an HTML table:
function ShowCreditsWithCustomVariables()
{
var fieldNames = ['customVariable1', 'customVariable2'];
var pCredits = GetPanelistCreditsWithCustomVariables(10, fieldNames);

var txt = "<table>\n"


txt += "<tr><td>Date</td><td>Project</td><td>Points</td><td>Custom
Variable 1</td><td>Custom Variable 2</td></tr>\n";
for(var i : int = 0;i<pCredits.length;i++)
{
txt+="<tr><td>"+pCredits[i].Created+"</td>";
txt+="<td>"+pCredits[i].SurveyId+"</td>";
txt+="<td>"+pCredits[i].Credit+"</td>;
txt+="<td>"+pCredits[i].CustomFieldValues[0] +"</td>;
txt+="<td>"+pCredits[i].CustomFieldValues[1] +"</td></tr>\n";
}
txt += "</table>\n";
return txt;
}

- 137 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.13. Standard and Professional Panels


This section describes functions that can be used in registration and profile update surveys linked to a Standard or
Professional Panel to add and update panelists.
Standard Panels and Professional Panels are Forsta add-ons. If you do not have access to this functionality, contact
your Forsta account manager for more information.
Registration and profile update surveys are set up as regular Forsta surveys, and are linked to the panel database
through a setting on the Project Management > Overview page General tab:

This setting will allow scripts in the survey to add new panelists to the panel database and retrieve and update data
from the panel database for the current panelist. Very often the registration and profile update surveys will be linked
from the Panel Portal.

10.1.13.1. CreatePanelist
In a registration survey linked to a Panel as described below, the person registering to participate in the panel can be
asked for email (which will be used as the login name and unique identifier), password and other information. The
panelist can be added to the panel database with the CreatePanelist function:
CreatePanelist(fieldNames, fieldValues)
CreatePanelist will return the panelist id (positive integer) if the insert succeed, or a negative integer if the insert of a
new panelist fails, for example because a panelist is already registered with the provided email address (see below).
The parameters are both arrays of Strings: fieldNames are names of the fields in the panel database to insert data
into, and fieldValues are the corresponding values to insert into these fields. fieldNames needs at least to
include “email”, but if the panel database has other user provided unique fields, these fields need to be included as
well.
The codes returned from the insert of a new panelist are listed below. A negative code (less than zero) represents an
error and means that the panelist creation did not succeed.

Code Description
>0 The panelist was created successfully. A new panelist record is added to the database and the panelist
id is returned.
-1 Error on the survey end, for example not being able to connect to the panel database etc.

-2 The unique constraint is violated, i.e. a panelist already exists with the provided values in the unique
fields (email + any user provided unique fields)

-3 Other database errors when inserting the new panelist.


-5 The password failed on one or more of the password complexity rules, according to the Panel settings
for password complexity.

Inserting a new Panelist in a Panel


In a registration survey that is linked to a Panel as described above, there is an open text question with question id
“email”. In the validation code of this open text question the following script can be included to insert the new panelist
in the Panel database, and provide an error message if the insert fails:

- 138 -
Forsta Confidential Forsta v2022 Scripting Manual

var fieldNames : String[] = ["email"];


var fieldValues : String[] = [f('Email')];
var result = CreatePanelist(fieldNames, fieldValues);
if(result<0 && result!= -2 && result!= -5)
{
RaiseError();
SetErrorMessage(LangIDs.en,"Unknown error: Couldn't register with this email address. Error code:" + result);
}
else if(result == -2)
{
RaiseError();
SetErrorMessage(LangIDs.en,"Can't register with this email address. It is already in use.");
}
else if (result == -5)
{
RaiseError();
SetErrorMessage(LangIDs.en,"Password does not comply with password complexity rules. Please choose a different
password.");
}

10.1.13.2. UpdatePanelVariables
If a survey is linked to a Panel as described above, and the panelists are identified either through panelistid being
included in respondent table (a survey you have sampled to), because the survey is opened within a protected page
(requires login) in the panel portal (profile update), or because you have just inserted this panelist with the
CreatePanelist function (registration survey), you may use the UpdatePanelVariables function to update variables
in the panel database.
UpdatePanelVariables(fieldNames, fieldValues)
The parameters of the UpdatePanelVariables function are both arrays of Strings: fieldNames are names of the
fields in the panel database to update, and fieldValues are the corresponding values to set in these fields.
UpdatePanelVariables will return a negative integer if the update fails:

Code Description
0 Update successful.
-1 Error on the survey end, for example not being able to connect to the panel database etc.

-2 The unique constraint is violated, i.e. another panelist already exists with the provided value(s) you are
trying to set for (one of) the unique field(s) (email + any user provided unique fields).

-3 Other database errors when updating the panelist.


-4 The panelist does not exist.
-5 The password failed on one or more of the password complexity rules, according to the Panel settings
for password complexity.

Update Panel Variables in a Panel

- 139 -
Forsta v2022 Scripting Manual Forsta Confidential

Here is an example from a survey linked to a Panel as described above, where the questions gender, dateofbirth,
USstate, householdsize, carowner, empstatus, marstatus and email are asked. A hidden open text question
status_desc is used to store the status returned from the update call. The following script can be placed in a script
node to update these variables in the panel database for the current panelist:
var fieldNames : String[] =
["gender","dateofbirth","USstate","householdsize","carowner","empstatus",
"marstatus","email"];
var fieldValues : String[] =
[f('Gender'),f('dateofbirth'),f('USstate'),f('householdsize'),f('carowner
'),f('empstatus'),f('marstatus'),f('email')];
var result = UpdatePanelVariables(fieldNames, fieldValues);

if(result <0 && result!= -2 && result!= -4 && result!= -5)


{
f('status_desc').set("Unknown error. Error code:" + result);
}
else if(result == -2 )
{
f('status_desc').set("Update of email address failed. It is already in
use for another panelist.");
}
else if(result == -4 )
{
f('status_desc').set("Panelist does not exist in the panelist
database.");
}
else if(result == -5 )
{
f('status_desc').set("Password does not comply with password complexity
rules.");
}
else
{
f('status_desc').set("Succesfully updated.");
}

10.1.13.3. GetPanelVariables
If a survey is linked to a Panel as described above, and the panelists are identified either through panelistid being
included in respondent table (a survey you have sampled to) or because the survey is opened within a protected page
(requires login) in the panel portal (profile update), you may use the GetPanelVariables function to update
variables in the panel database.
GetPanelVariables(fieldNames)

Note: If this function is used in a survey, then the survey must be launched as a Limited survey. Failure to do
this will result in an error message being generated for each respondent who attempts but fails to enter the
survey either because they are not uploaded or because they do not enter via a portal.

GetPanelVariables will retrieve values from the fields provided in fieldNames (array of Strings) and return these
values. The data types will be according to the question types (for example date, numeric, open text etc.).

Retrieving Data for a Panelist in a Panel


The following script can be placed in a script node in the beginning of a profile update survey linked to a panel as
described above to retrieve the fields gender, dateofbrith, USstate, carowner, empstatus, marstatus and email and set
these values in the corresponding questions in the survey. The script will skip empty values (empty string “” or null),
and also shows how true and false for the carowner variable, which is a Boolean in the Panel, are converted to codes
1 and 0.

- 140 -
Forsta Confidential Forsta v2022 Scripting Manual

var fieldNames : String[] =


["gender","dateofbirth","USstate","householdsize","carowner","empstatus",
"marstatus","email"];
var variables = GetPanelVariables(fieldNames);
for(var i=0;i<fieldNames.length;i++)
{
if(fieldNames[i]=="carowner")
{
if(variables[i])
f(fieldNames[i]).set("1")
else
f(fieldNames[i]).set("0")
}
else if(variables[i]!="" && variables[i]!=null)
f(fieldNames[i]).set(variables[i]);
}

10.1.13.4. UpdateSurveyHistoryPanelVariables
The function UpdateSurveyHistoryPanelVariables replaces UpdateSurveyHistoryVariables, and is used for updating
the survey history of a panelist directly from a script in the panel survey. It requires that the survey from which it is
called is linked to the panel as described previously.
UpdateSurveyHistoryPanelVariables(fieldNames, fieldValues)
fieldNames and fieldValues are both arrays. fieldNames holds the variable names of the survey history variables you
want to update, and fieldValues the corresponding values to assign to them.

Update Survey History Variables in a Panel


This is an example from a survey linked to a Panel as described, where sample has been uploaded from a sample
job. The response to a question "surveyrating", asked at the end of the survey, is to be set in the panel's survey
history.
var fieldNames : String[] = ["surveyrating"];
var fieldValues : String[] = [f('surveyrating')];
UpdateSurveyHistoryPanelVariables(fieldNames,fieldValues);

10.1.13.5. UpdateSurveyHistoryVariables (obsolete)


The function UpdateSurveyHistoryVariables is used for updating the survey history of a panelist directly from a
script in the panel survey, in a similar way to UpdateSurveyHistoryPanelVariables, but requires providing the
panelistID and jobNumber in addition to the variables to update and their values. It requires that the survey from which
it is called is linked to the panel as described previously.
UpdateSurveyHistoryVariables(panelistIdString, jobNumber, fieldNames,
fieldValues)
panelistIDString (string) is the panelistid (the responseid in the panel database). jobNumber (string) is the
sample job number. fieldNames and fieldValues are both arrays. fieldNames holds the variable names of the
survey history variables you want to update, and fieldValues the corresponding values to assign to them.
It is recommended that you use UpdateSurveyHistoryPanelVariables instead, as that is simpler. However
UpdateSurveyHistoryVariables is still supported.

10.1.13.6. IsFromCommunityPortal and GetCommunityPortalReturnUrl


When the registration and/or profile update survey is opened from the Panel Portal, it will be opened within a frame in
the Panel Portal. The functions IsFromCommunityPortal and GetCommunityPortalReturnUrl are provided to
seamlessly handle redirecting back to the Panel Portal for panelists that have opened the survey from within the Panel
Portal.
IsFromCommunityPortal()

- 141 -
Forsta v2022 Scripting Manual Forsta Confidential

IsFromCommunityPortal() returns true if the survey is opened from the Panel Portal and false if not. The
function can be used to determine when to redirect to the Panel Portal Url provided by the
GetCommunityPortalReturnUrl function.
GetCommunityPortalReturnUrl()
GetCommunityPortalUrl() returns a URL that can be used to redirect back to the Panel Portal, with
authentication (so that the panelist does not need to log on again if he/she was already logged in).

Redirect back to Panel Portal


The following script can be placed in a script node at the end of a survey to redirect back to the Panel Portal for
panelists that open the survey from the Panel Portal:
if(IsFromCommunityPortal())
{
Redirect(GetCommunityPortalReturnUrl());
}
else
{
Redirect("http://www.confirmit.com");
}

10.1.13.7. IsFieldValueTaken
In Professional and Standard Panels it is possible to set panel variables to be unique. That means that each panelist
must have a unique value in this field. The isFieldValueTaken function can be used in panelist recruitment surveys to
check if any previous respondents have selected the same value in a given field.
isFieldValueTaken(fieldName, value)
isFieldValueTaken returns true if there is already a panelist in the sample with the provided value (string) in the
question with question id fieldname (string), false otherwise.
It can be used in the validation code of the question defined in "uniqueid" in a panel survey:
if(isFieldValueTaken("uniqueid", f("uniqueid").get()))
{
SetQuestionErrorMessage(LangIDs.en,"The value in uniqueid is already
taken. Please input a different value.");
f("uniqueid").set("");
RaiseError();
}
The function can also be used in the same way in ordinary projects to check that the value entered in a question with
a given question id is unique. If the function is used in ordinary projects, performance will be improved if the Indexed
property is set on the question being checked. If the function is used to check variables in a panel, again performance
will be improved if the Indexed property is set on the variable being checked.

Note: This function is not supported in RDG, quick-test and external test mode.

When connected to a panel (Professional, Standard or Basic), this function will look in the panel database to see if the
value is taken. When used in a normal survey not connected to a panel, the function will look in the survey database.
Note that if the qid referenced in isFieldValueTaken(qid,value) does not exist in the panel database the function will
always return true.

10.1.13.8. isEmailTaken
The isEmailTaken function is used in panelist recruitment surveys in the same way as isUsernameTaken; to
check if any previous respondents have registered with the same email address.
isEmailTaken(email)
isEmailTaken returns true if there already is a panelist in the sample with the provided email (string), false
otherwise.

- 142 -
Forsta Confidential Forsta v2022 Scripting Manual

The function can also be used in the same way in ordinary projects, to check that the value entered in a question with
question id email is unique. If the function is used in ordinary projects, the indexed property should be set on the email
question to improve performance.

Note: This function is not supported in RDG, quick-test and external test mode.
Note: If you call the function from a survey that is connected to a panel (for example a registration/update
profile survey), then the string argument is compared with the email column in the panel, while if the function
is called from a survey that is not connected to any panel, then the argument is compared to the email
column in the response database of the actual survey.

10.1.13.9. DeleteCurrentResponse
Since the data of registration and profile update surveys are usually posted back to the panel database before the end
of these surveys, it is usually not necessary to keep the data in the survey itself. Therefore a function is provided to
enable deletion of the entire response at the end of the survey after all update scripts have been run:
DeleteCurrentResponse()
DeleteCurrentResponse will remove the entire record with all responses from the survey database.
When DeleteCurrentResponse is used at the end of the survey in a script node, it should be followed immediately by a
redirect script. This is because any attempt to open a survey page (including the end page) after the record has been
deleted will give an error, as the respondent no longer exists (see IsFromCommunityPortal and
GetCommunityPortalReturnUrl on page 141 for more information).

10.1.13.10. Functions for Sample Only

RedirectToExternalSurvey and GetExternalSurveyState


Note: “Sample Only” is a Panel add-on to be used by access panel providers who, as a part of their business,
sell sample to other companies, on projects where they do not perform the data collection themselves. Any
other usage of this functionality is prohibited. Contact your Forsta account manager for more information.

With the "Sample Only" add-on enabled, you can upload a repository of external survey links to the sample job. To
upload the links:
Create a text file (.txt) with 'Link' as the only column header and the external survey links listed, one link per row. On
"Job Information", the interface shown below is available to upload external survey links to the job:

These survey links will then be included in the sample file(s). These can then be uploaded to a Forsta survey, which
must be linked to a Panel on Project Overview:

This project is used for:

• Emailing survey invitations and reminders to panelists


• Redirecting panelists to the external survey links
• Update status, panelist credits etc. if panelists are redirected back to the survey when finished in the external
survey link with status.
You can also add questions to this survey; you could for example ask panelists to rate the survey experience etc.
when they are finished with the external survey, or you may need an initial screener before respondents are
redirected. Note however that you are NOT allowed to use this redirect survey for general data collection.

- 143 -
Forsta v2022 Scripting Manual Forsta Confidential

The following function can be used in this survey to handle redirects and statusing:
RedirectToExternalSurvey(queryString)
RedirectToExternalSurvey will redirect the panelist to the url uploaded to the background variable
"ExternalSurveyLink", with querystring (optional, String) added to the link. querystring can be used if you need
to send in some values with the link. This can be useful if the system running the survey is capable of fetching these
values sent in with the link.
For example, if you have a background variable gender in the sample file, you could send in that value with the
external survey link by using:
RedirectToExternalSurvey("?gender="+f("gender").get())
If you send in several parameters like this, then you must separate them with the ampersand (&) character.
The RedirectToExternalSurvey function will also set a session cookie that will be used when panelists are
redirected back to the survey after finishing the external survey, to identify the panelist and set the correct status on
the panelist for this job.
At the end of the external survey, there should be a redirect back to the survey with the correct status in the survey
link. This status will then be set both on the redirect survey, and back to the panel (in survey history). The statusing
URL is one of the following:
http://<server>/wix/<pid>.aspx?status=complete
http://<server>/wix/<pid>.aspx?status=screened
http://<server>/wix/<pid>.aspx?status=quotafull
http://<server>/wix/<pid>.aspx?status=incomplete
http://<server>/wix/<pid>.aspx (this will default to complete)
<server> is to be replaced with either survey.confirmit.com or survey.euro.confirmit.com if you are a SaaS user, or
your system’s survey domain if you are an On-Premise user. <pid> is to be replaced with the project id of the survey
that is used for the redirect.
When panelists are redirected back, the system will retrieve the necessary information from the cookie to identify the
panelist so that the right status is set, and open the survey after the redirect. The survey will be opened on the node
following the script node with the Redirect script (for example a question, a script node or a stop node). Additional
questions or scripts, for example to set Panelist Credits (points), can be placed after the Redirect script to be executed
when the panelist is redirected back to the redirect survey. The redirect survey will be opened automatically at the
point where the redirect was done when the panelists return from the external survey, due to the details stored in the
cookie.
The cookie is a "session cookie", so is removed when the panelist closes his/her browser.
The function GetExternalSurveyState can be used to keep track of what state the panelist is in, i.e. whether
status has been set or not.
GetExternalSurveyState()
GetExternalSurveyState will return one of the following state codes:
ExternalSurveyState.NONE
ExternalSurveyState.NOT_STARTED
ExternalSurveyState.IN_PROGRESS
ExternalSurveyState.STATUS_SET
The GetExternalSurveyState function is useful if a panelist has disabled cookies in his/her browser. If the
session cookie cannot be found, you will be unable to automatically update the panelist status. To treat this special
case, you can include a condition with the expression
GetExternalSurveyState() == ExternalSurveyState.NONE

- 144 -
Forsta Confidential Forsta v2022 Scripting Manual

followed by a stop node so that these panelists don't cause any errors in scripts you have for example to update panel
variables or points. The text on this stop node could for example notify the panelist that their points status was not
updated automatically and that they will have to wait some days for this to be done, depending on the procedures for
this. It is probably a good idea to flag these incidents by setting a hidden variable as well so that you keep track on
how often it happens.

Note: The statusing survey must have "Encrypt system request parameters" (default) enabled in Survey
Settings/Web for statusing to work.

If you follow the procedure described above, "Interview complete - Sample Only" units will be logged for completes
instead of regular "Interview complete - CAWI ". These units are solely intended to be used by access panel providers
who, as a part of their business, sell sample to other companies, on projects where they do not perform the data
collection themselves. Any other usage of this functionality is prohibited. The following must be in place for the
"Interview complete - Sample only" units to be logged:

1. The project must be linked to a Standard or Professional Panel.


2. The respondent must have a value in the panelistid column in the respondent table.
3. The respondent must have a value in the External Survey Link column in the respondent table.
All of this happens automatically when uploading sample from the sample job if you follow the procedure described
above.

10.1.13.11. AddPanelSurveyHistory
This function is used to create a survey history entry for the current panelist, it is used in scenarios where the panelist
is participating in a survey linked to the panel that they are a member of, but have not been directly sampled to.
AddPanelSurveyHistory( panelistId, jobNumber)
The input parameters are strings: panelistId is the panelist’s ID from the linked panel and jobNumber is the job
number in the panel that the survey history entry will be associated with.
The following syntax can be used to update the current panelist in job number 10 in the linked panel. An error will be
reported if the insert fails:
AddPanelSurveyHistory(GetRespondentValue('PanelistId'),"10");
The following criteria must be met for the panelist’s survey history to be updated successfully:

1. The survey must be linked with a Standard or Professional Panel.


2. The specified panelist ID must exist in the panel.
3. The survey needs the panel fields in the Respondent table: panelistid, jobnumber and runnumber
On successful execution of the function, the survey panel history for the specified panelist will be updated in the panel
for this survey. If the job number does not exist, a new job will be created with this job number.

Note: This function is required when a Survey Router is used to route panelists from one survey to another
where the routed-to survey is one that the panelist was not sampled to.

10.1.14. Basic Panels


This section describes two functions available for Basic Panels but which also may be used in ordinary projects.

- 145 -
Forsta v2022 Scripting Manual Forsta Confidential

Note: Basic Panels is a Forsta add-on. If you do not have access to this functionality, contact your Forsta
account manager for more information.

10.1.14.1. isUsernameTaken
In Basic Panels, the unique identifier for a panelist is the panelist's username. The IsUsernameTakenfunction is
used in panelist recruitment surveys to check if any previous respondents have selected the same username.
isUsernameTaken(userName)
isUsernameTaken returns true if there is already a panelist in the sample with the provided userName (string) in
the question with question id "username", false otherwise. Note that the question id must be "username".
It is used in the validation code of the username question (mandatory) in a panel survey:
if(isUsernameTaken(f("username").get())){ SetQuestionErrorMessage(LangI
Ds.en,"User name taken. Please choose another user
name."); f("username").set(""); RaiseError();}
The function can also be used in the same way in ordinary projects, to check that the value entered in a question with
question id "username" is unique (note that the question must have the question id "username"). If the function is used
in ordinary projects, the indexed property should be set on the username question to improve performance.

Note: If you call the function from a survey that is connected to a panel (for example a registration/update
profile survey), then the string argument is compared with the username column in the panel, while if the
function is called from a survey that is not connected to any panel, then the argument is compared to the
username column in the response database of the actual survey.

10.1.15. Classification Functions


Use these functions to check that the data input by the respondents, for example date and age information, is of the
correct format.

10.1.15.1. IsNumeric and IsInteger


IsNumeric( argument )
IsNumeric returns true if the argument (string) is numeric.
IsInteger( argument )
IsInteger returns true if the argument (string) is an integer.

Checking that a Response in an Open Text List Question is an Integer


If you have an Open Text List question details, you can have text boxes for "name", "title", "address", "age" etc. If we
want integers only to be allowed for "age", you have to provide validation code for that specific row in the open text list
question. So, if "age" has code 4 in the open text list question details, we can use this validation code:
if(!IsInteger(f("details")["4"])) //Age not integer
{ RaiseError(); SetQuestionErrorMessage(LangIDs.en,"Please use integers
only for \"age\"."); }
You could use InRange as well if you want to check that the value answered is in a reasonable range for age (see
Range on page 77 for more information).

10.1.15.2. IsDateFmt and IsDate


IsDateFmt( argument,format )
determines whether the provided argument (string) is a valid date according to format (string).
Within a date format, the following character sequences have special significance:

Y Year, four digits.

- 146 -
Forsta Confidential Forsta v2022 Scripting Manual

YY Year, two digits.


YYYY Year, four digits.
M Month number, one or two digits.
MM Month number, exactly two
digits.
D Day number, one or two digits.
DD Day number, exactly two digits.

All other characters are treated as separators.


All parts are optional. If omitted, then the system date is used to determine month and year and the number 1 is used
for the day.
IsDate( day,month,year )
IsDate determines whether the provided year, month and day combination (all strings) constitutes a valid
Gregorian date.
The month and year arguments are optional. If they are not provided then the current month and/or year is used.
For both IsDateFmt and IsDate century interpolation for 2-digit years is handled with a break-point value of 10:
values between 0-10 are interpreted as the years 2000-2010, while 11-99 is treated as 1911-1999.
IsDateFmt and IsDate return an object with the properties day, month and year if the date is valid and in the
correct format, null otherwise. A general description of objects follows (see Objects on page 164 for more
information), and examples where the object returned from IsDateFmt and IsDate and the properties day, month
and year are used are given.
Both IsDateFmt and IsDate can be used in conditions to check for valid dates. If the date is valid and in the correct
format, an object is returned. Used in a condition this will be interpreted as true. If the date is invalid or in wrong
format, null will be returned. Used in a condition this will be interpreted as false.

Note: The Date question type gives a date input box and calendar popup, and has built-in validation so that
you do not need to use IsDate or IsDateFmt to validate the date.

Validating Date Format of Open Text Date Question


If you have an open text question date1 and want the respondent to answer in a particular format, you can use
IsDateFmt. IsDateFmt will both check that the format is correct, and that the date is a valid date.

Here is a script you can use in the validation code of such a question:
if(!IsDateFmt(f("date1").get(),"YYYY-MM-DD"))
{ RaiseError(); SetQuestionErrorMessage(LangIDs.en,"Invalid date.
Please correct. Use the format YYYY-MM-DD"); }

Validating Date with Drop-downs for the Date Parts


You can also set up date in three questions with drop-downs: One for year, one for month and one for day. To get
these on the same line, you can place three grid questions in a 3D grid question as here:

- 147 -
Forsta v2022 Scripting Manual Forsta Confidential

The 3D grid's answer list will just have one item:

The grid's answer list will be years, months and dates. It is important that you define codes that are equal to the
number of the years, months (1-12) and dates (1-31):

- 148 -
Forsta Confidential Forsta v2022 Scripting Manual

The question will then look like this:

Here is a script you can use in the validation code of such a question, using the IsDate function with the different
date parts (the grid questions) as arguments:
if(!IsDate(f("day")["1"].get(),f("month")["1"].get(),f("year")["1"].get()
))
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Invalid date. Please correct.");
}

10.1.15.3. IsEmail
IsEmail( argument )

- 149 -
Forsta v2022 Scripting Manual Forsta Confidential

IsEmail checks whether the argument has the format of a valid email address. It returns true if it has, false
otherwise.

Note: the function does not attempt any name look-ups or address verification, it just checks that the format
is valid (i.e. includes an @ character etc.).

Validation of Email Address Format


An open text question email is used to collect the respondent's email address. To check that the answer is a valid
email address, use the following code in the validation code field:
if(!IsEmail(f(CurrentForm())))
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please provide a valid email
address.");
}

Note: In Survey Designer, users can enable the ‘Email’ property on a Text question. This removes the need
for validation script to check that the answer adheres to email format.

10.1.15.4. IsNet
IsNet(quadIP,quadNet,quadMask)
Determines whether an IP address belongs to an Internet network.

Argument Description
The IP address, in quad form (X.X.X.X.).
quadIP

quadNet The network number, in quad form.


quadMask An optional mask, in quad form, if sub netting is used.

If no mask is provided then the number of bits that constitute the network part of the address is determined from the
address class type. In this case the function returns true if the IP address' network number is identical to the supplied
network number and it has a non-zero local address. Otherwise it returns false.
If a mask is provided then the function returns true if the IP address' network and subnet parts are identical to the
one supplied and the host number part is non-zero. Otherwise it returns false.
You can use the RequestIP function to get the respondent's IP address (see RequestIP on page 95 for more
information).

Excluding Respondents from Specific Networks


Assume you wish to exclude respondents with the network number "192.168.18.0", subnet mask "255.255.255.0"
from taking a specific survey (for example because they work for the company that is running the survey).
Then you may place a condition in the beginning of the questionnaire with the following expression to screen those
respondents:
IsNet(RequestIP(), "192.168.18.0", "255.255.255.0")

10.1.16. General Utilities


Use these functions to send emails etc.

10.1.16.1. SendMail
SendMail(from,to,subject,body,cc,bcc,mailformat,bodyformat,codepage)

- 150 -
Forsta Confidential Forsta v2022 Scripting Manual

SendMail can be used to send an email from inside a survey. For information on sending of multipart emails (see
SendMailMultipart on page 153 for more information).
Arguments:

Argument Description

From Message sender (string)

to Recipient's address (string)

subject Message subject line (string)

Body Message body (string)

cc* Carbon Copy (string)

bcc* Blind Carbon Copy (string)

mailformat* (int) (obsolete)

bodyformat* (int)
0 – HTML, 1 – Plain text

codepage* (int)
The codepage the mail is to be sent with. 1252 is Western European, 65001 is
Unicode (UTF-8).

*) optional

The last 5 arguments are optional, but if you include any of them, you have to include all arguments that precede
them. For example, if you do not want a carbon copy (cc), just use an empty string ("") for that argument (see
APPENDIX D: Codepage on page 283 for more information).

Send Confirmation Email at the End of a Survey


Here is an example of a script placed at the end of a pop-up survey to thank the respondent for participating in the
survey. The respondent has provided her or his email address in an open text question called email:
//build body of email:
var body : String = "You have just completed a survey powered by
Confirmit.\r\n\r\n";
body += "We would like to thank you very much for your
contribution.\r\n\r\n";
body += "Best Regards\r\n\r\n";
body += "Confirmit\r\n";

//send mail:
SendMail("[email protected]",f("email"),"Thank
you!",body,"","[email protected]");

- 151 -
Forsta v2022 Scripting Manual Forsta Confidential

The email will be sent to the respondent, with a blind copy sent to "[email protected]". The respondent will not know
that this copy has been sent as the address is in the bcc field. You must include an empty string ("") for the cc
argument if you do not want to cc anybody but do want to bcc as in this example. If you need more than one email
address in either to, cc or bcc, separate the addresses with semi colons (;) inside the string, e.g.
"[email protected];[email protected]".

Invitation Email to a Different Part of the Same Survey


We want a survey to start as a pop-up survey where the respondent registers email (with validation of the email
address) and name. Based on that, an email is to be sent to the email address with the url to the rest of the survey,
and the pop-up survey is to terminate.
When the respondent opens the url in the mail, he or she should get a page with a text that includes his or her name.
Build a questionnaire like this:

The first condition checks if there is an answer to the email question. The email question is required, so if it has no
answer the respondent should get the first part of the survey.
Then name and email questions follow. In the email question, use the following validation code:
if(!IsEmail(f(CurrentForm()))))
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please provide a valid email
address.");
}
After the email question there is a script node, which does the emailing (change "survey.confirmit.com" if you are not
using Confirmit's ASP):
var body : String = "Thank you for registering.\r\n\r\n";
body += "Here is the url to your follow up survey:\r\n";
body += GetRespondentUrl()+"\n";

SendMail("[email protected]",f("email"),"Follow up",body);
Then there is a stop node to end the first part of the interview. When the respondent re-opens the interview with the
url, he/she is brought into the same interview with the data from the first part. So since there now is an answer to the
email question, the first part will be skipped and the respondent will be brought to the info node (i4).
However, by default, when a condition in Forsta evaluates to false, the interview engine removes all answers to
questions in the THEN-branch. This ensures that you get consistent data in your surveys and do not have to do data
cleaning. But here, this would mean that the answers to name and email would be deleted, and that is not what we
want – we are going to use name in part 2 of the interview.
Fortunately there is a property on conditions that can be used in situations like these: "Do not perform delete". When
this property is checked, the interview engine will never remove answers in any of the branches (THEN/ELSE).

- 152 -
Forsta Confidential Forsta v2022 Scripting Manual

To pipe in the name in the first info node (i4), use the code below:
^f("name")^

10.1.16.2. SendMailMultipart
SendMailMultipart(from,to,subject,bodyText,bodyHtml,cc,bcc,codepage)
SendMailMultipart can be used to send a multipart email from inside a survey. A multipart email is an email
where the body text can be defined both as plain text and as HTML. The recipient’s mail client will determine which
version is to be displayed to the recipient.
Arguments:

Argument Description

From
Message sender (string)

to
Recipient's address (string)

Subject
Message subject line (string)

BodyText
Message body, plain text (string)

BodyHtml
Message body, HTML (string)

cc*
Carbon Copy (string)

bcc*
Blind Carbon Copy (string)

Codepage*
(int) The codepage the mail is to be sent with. 1252 is Western European, 65001 is Unicode (UTF-8)
(default value).

*) optional

The last 3 arguments are optional, but if you include any of them, you have to include all arguments that precede
them. For example, if you do not want a carbon copy (cc), just use an empty string ("") for that argument (see
APPENDIX D: Codepage on page 283 for more information).

- 153 -
Forsta v2022 Scripting Manual Forsta Confidential

10.1.16.3. SendPdfMail
The SendPdfMail function allows the generation and emailing of a PDF file from a survey with for example a
summary of the respondent's answers. Typically the file is sent to the respondent, but it could also be sent to
someone who is to review the respondent’s answers. Note that you can also send PDF mail with copies (see
SendPdfMailWithCopy on page 155 for more information).

Note: PDFs are only sent when the device is synched with the server.

The syntax of the function is:


SendPdfMail(html,emailSender,emailReceiver,emailBody,emailSubject,outputF
ileName,pdfPageSize,pdfOrientation)
Arguments (all strings):

Argument Description

html
A string with the html that the PDF file should be created from.

emailSender
The sender of the message.

emailReceiver
The recipient's address.

emailBody
The message body text (optional).

emailSubject
The message subject (optional).

outputFileName
The filename of the pdf file (optional). Note that the filename can only contain alphanumeric
characters. Do not specify the extension of the file.

pdfPageSize The paper size for which the PDF is formatted (optional). Valid options are A3, A4, A5, B4, B5,
Legal, Letter and Tabloid.
pdfOrientation The orientation of the page (optional). Valid options are Landscape or Portrait.
companyId The company id (required if pdfPageSize and/or pdfOrientation are included in the function). Each
company has one id. Note that normal users do not have access to this information; you must
contact Forsta support to retrieve it.
useNewPdfEngin (Required if PaperSize and/or Orientation are included in the function) This is a Boolean value
e which can be either true or false.

Figure 5 Examples of functions

As the content of the PDF file is a string containing HTML, there is considerable flexibility concerning the layout and
content of such a respondent-specific report.
If no subject is provided, the subject of the email will be “Respondent Report”. If no filename is provided, the name of
the pdf file will be “respondentreport”.

- 154 -
Forsta Confidential Forsta v2022 Scripting Manual

The call to the function initiates a task that runs on the batch servers to generate and send a zipped PDF file. This
means that, depending on the queue of tasks on the batch server, there may be a delay in producing and sending the
file. If the PDF report is to be sent to the respondent, it is recommended that the respondent is informed of this
possible delay. The function will not run in RDG mode.
For SaaS customers there is a charge for each of these reports, just as for PDF exports from Reportal.
The PDF-software does not parse anchor tags; it only adds the link text. So to have clickable links in the PDF file that
is generated with SendPdfMail, you must include the URL itself.
http://www.confirmit.com
NOT:
<a href=” HYPERLINK "http://www.confirmit.com/”%3eLink" http://www.confirmit.com/”>Link text</a>
If you want blue text and underline, you can define this in a <span> tag:
<span style="text-decoration: underline; color: blue">HYPERLINK "http://www.confirmit.com%3c/span"
http://www.confirmit.com</span>

Sending a PDF to the respondent with answers from the survey


Here is a short example where the respondent answers questions on name, email, age and gender. Following
these questions is a script that generates and sends a PDF file with the answers the respondent has given:
var html ="<html><body>\n";
html += "<h1>Answers for "+f("name").get()+"</h1>\n";
html += "<table><tr><th>Question</th><th>Answer</th></tr>\n";
html +=
"<tr><td>"+f("email").label()+"</td><td>"+f("email").get()+"</td></tr>\n"
;
html +=
"<tr><td>"+f("age").label()+"</td><td>"+f("age").get()+"</td></tr>\n";
html +=
"<tr><td>"+f("gender").label()+"</td><td>"+f("gender").valueLabel()+"</td
></tr>\n" ;
html += "</table>\n";
html += "</body></html>\n";

SendPdfMail(html,"[email protected]",f("email").get(),"Here are
your responses to the survey.","Your responses","responses");

Note: Non-ASCII characters are not accepted by the PDF creator. If non-ASCII characters must be used, write
valid HTML for the required character and include a metatag such as the following: <meta http-
equiv="content-type" content="text/html;charset=utf-8" />

10.1.16.4. SendPdfMailWithCopy
The SendPdfMailWithCopy function is an extension of the SendPdfMail function, giving you the possibility to
copy the mail to others. The function allows the generation and emailing of a PDF file from a survey with for example
a summary of the respondent's answers.

Note: PDFs are only sent when the device is synched with the server.

The syntax of the function is:


SendPdfMailWithCopy(html,emailSender,emailReceiver,cc,bcc,emailBody,email
Subject,outputFileName,pdfPageSize,pdfOrientation)
Arguments (all strings):

Argument Description
html A string with the html that the PDF file should be created from.

- 155 -
Forsta v2022 Scripting Manual Forsta Confidential

emailSender Message sender.


emailReceiver Recipient's address.
cc The email will be copied to these addresses. Separate multiple addresses with
comma. The addresses will be visible to other recipients.
bcc The email will be copied to these addresses. Separate multiple addresses with
comma. The addresses will not be visible to other recipients.
emailBody The message body text (optional).
emailSubject Message subject (optional).
outputFileName The filename of the pdf file (optional). Note that the filename must only contain
alphanumeric characters. Do not specify the extension of the file.
pdfPageSize The paper size for which the PDF is formatted (optional). Valid options are A3, A4,
A5, B4, B5, Legal, Letter and Tabloid.
pdfOrientation The orientation of the page (optional). Valid options are Landscape or Portrait.
companyId The company id (required if pdfPageSize and/or pdfOrientation are included in the
function). Each company has one id. Note that normal users do not have access
to this information; you must contact Forsta support to retrieve it.
useNewPdfEngine (Required if PaperSize and/or Orientation are included in the function) This is a
Boolean value which can be either true or false.

Note that if this function is used, both cc and bcc must be used.
For further details, see SendPdfMail (see SendPdfMail on page 154 for more information).

10.1.16.5. Redirect
Redirect(url,{noexit})
Redirect can be used to redirect the respondents to a different site (url).

Important
If a redirect is included at the end of the survey, it is important that the interview status is also set using the
SetStatus function (see GetStatus and SetStatus on page 87 for more information).

Note: The use of redirects, quotas, status-screened or other solutions with the principle purpose of avoiding
the survey "complete" status being reached by a respondent having offered a reasonable amount of
responses, is prohibited and will be regarded as an attempt to avoid transaction fee obligations to Forsta.

noexit is a Boolean. It is optional, and is used when you want the respondents to be able to reenter the survey, for
example if you redirect out of the survey to another url, and then at some point the respondents are redirected back
to the survey again (with r (respid) and s (sid)). This is especially important if the survey is set up without "Allow user
to modify answers after the interview is complete". With noexit as true, the respondent will be allowed to reenter
the survey. With noexit as false (default), the respondent will not be allowed reentry to the survey.

Redirect to Another Site Before the End Page


If you want to send the respondent to another site (here: Google) before he or she reaches the default end-of-survey
page in Forsta, you can use a script as below:
SetStatus("complete");
SetInterviewEnd();
Redirect("http://www.google.com",false);
Redirect is used in combination with SetStatus and SetInterviewEnd so that the respondent is given the
correct status and end time stamp before being redirected out of the survey.

- 156 -
Forsta Confidential Forsta v2022 Scripting Manual

Note: The use of scripted Redirect() to jump into or out of questions that are in Call Blocks will cause
problems and should not be attempted. A key attribute of Call Blocks is that they can be entered from
multiple points in a survey, so the survey engine will not have a specific “entry-point” that has been used to
enter that call block. Therefore when the Call Block finishes it does not know where in the main body of the
survey to return to, and the survey will simply error. Refer to the separate Survey Designer user guide for
further details on Blocks.

10.1.16.5.1. Opening a Specific Survey Page or Call Block


If you would like to open a specific survey page with an internal redirect, then you can either use
RedirectToRespondentUrl() (see RedirectToRespondentUrl on page 84 for more information), or Redirect together
with GetRespondentUrl() (see GetRespondentUrl on page 82 for more information).
Example:
Redirect(GetRespondentUrl(“q9”), true);
Or:
RedirectToRespondentUrl(“q9”);
Both of these lines will redirect respondents to question q9 and allow the respondent to re-enter the survey again
(noexit = true). The difference between these two functions is that Redirect(GetRespondentUrl(),{noexit})) will display
the respondent unique link in the URL field, while RedirectToRespondentUrl will redirect without updating the URL
visible to the respondent.

Redirect between surveys, or between the survey and an external application with encrypted links:
You can use Redirect if you need to send the respondent to a different survey or another application. If you need to
send the respondent back into the survey again, then you can add the respondents sid value as a parameter to the
link, and use this to send the respondent back into its unique survey link.
Example:
In this example we will send the respondent from survey A into survey B, then when they complete survey B they are
sent back into survey A directly to question q4.

Figure 6 Redirecting from survey A to survey B

Figure 7 Redirecting from survey B back to survey A

Survey A includes the script “Redirect to survey B”. This will retrieve sid from the respondent link, and add this as a
parameter to the target link:
//Get the respondent unique survey link for question q4:
var UniqueLink = GetRespondentUrl("q4");

- 157 -
Forsta v2022 Scripting Manual Forsta Confidential

//split the survey link to retrieve sid:


var sid = UniqueLink.split("__sid__=");
//link to the target survey/application
var
RedirectToLink="https://survey.euro.confirmit.com/wix/p1873864785.aspx";
//send the respondent to the link added in RedirectToLink and add
parameter SourceSID to the link
Redirect(RedirectToLink + "?SourceSID=" + sid[1], true);
This will send the respondent into survey B (p1873864785 in this example). In the beginning of survey B we will have
a script to retrieve the “SourceSID” value from the link and add this into variable “SourceSID”.
Script “Retrieve sid from Survey link”:
var linkBackToSurveyA = Request("SourceSID");
f("SourceSID").set(linkBackToSurveyA);
At the end of survey B there is a script to redirect the respondent back to survey A and into question q4:
Script “Redirect back to survey A”:
Redirect("https://survey.euro.confirmit.com/wix/p1873864538.aspx?__sid__=
" + f("SourceSID").get(),true);

Redirect to specific question with unencrypted links:


If you for example use Redirect to redirect the respondent to another application, but want to send the respondent
back to the Forsta survey on a particular page, you can include a parameter in the survey link to specify which page is
to open. This parameter is __qid (two underscores + qid). Valid values are the question ids of any question on the root
level of the survey (outside loops). When opening a survey url with this parameter, the survey will open on the page
that contains the question indicated in __qid.
Example:
http://survey.confirmit.com/wix/pXXXXXXXX.aspx? __sid__=ww-
redcOmXd5s2yCeqAQYTjtCOc0bqXHg9QNh28l-FFg7WyktC2GBFh8qJPBNGtY0&__qid=q4
This will just open that particular page (here: the page with question q4). No attempt is made to transfer background
variables, set interview start, or save any data.
Similarly, if you use __gotoCallBlock=CallBlockID (two underscores + gotoCallBlock), you can direct respondents
directly to a specific call block. When the call block is finished, the interview will finish.

Note: To use parameter __qid and the __gotoCallBlock option, the “Disable unencrypted QID request
parameter” must be unselected in the Overview page > More Survey Settings > Options section (Survey
settings > General Options tab in Professional Authoring).

10.1.17. Survey Router Functions


This section describes functions that can be used in surveys linked to a Survey Router.
Survey Router is a Forsta add-on. If you do not have access to this functionality, contact your Forsta account manager
for more information.
Survey Router surveys are set up as regular Forsta surveys, and are linked to the Survey Router via the Survey
Router menu. A survey can be registered in one Survey router and this is shown on the Project Management >
Overview page General tab:

This setting will allow scripts in the survey to find project IDs to route the respondent/panelist to or perform the routing
itself.

- 158 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.17.1. GetAvailableSurvey
GetAvailableSurvey is used to get a Project ID that the respondent/panelist could be routed to based upon supplied
selection criteria.
GetAvailableSurvey(fieldnames{, projectList, mode})
The list of question IDs supplied in fieldNames (array of Strings). Up to 5 questions IDs can be supplied (this value is
configurable for On-Premise license holders) that you want to be checked by the Survey Router selection algorithm.
The list of optional project ID to be included/excluded from the selection criteria supplied in projectList (array of
Strings). Mode (Boolean) optional unless a projectList is supplied, determines whether the projectList is an inclusion
or an exclusion list, where true demotes an inclusion list and false denotes an exclusion list.
In the following example both "gender" and "age" questions are considered in the survey selection but both project IDs
"p1234567" and "p7654321" will be excluded from the selectable surveys.
var fieldNames : String[] = ["gender", "age"]
var projectList : String[] = ["p1234567", "p7654321"]
f("targetSurvey").set(GetAvailableSurvey(fieldNames, projectList, 0));
In this example the "gender" question is to be checked. If for example the respondent has answered the "gender"
question in the original survey by stating he is "male", then the survey routing algorithm will check the remaining
surveys in the group and ignore any surveys where the quota for males is already full. As in this case "gender" is the
only selection criteria required, the routing algorithm would now select the survey with the highest priority and open
that survey for the respondent.

Availability of the respondent's quota profile does not consider Optimistically populated (currently active) respondents;
only those that have completed the survey and have caused the quota cell to be incremented.
In the event several projects satisfy the selection criteria and they all have the same priority, a project will be selected
from the group at random.
In the event that no projects satisfy the selection criteria, no project IDs will be returned. When a potential project is
found, the system will verify that the respondent has not already participated in that specific survey (username in the
respondent table is used as the key); if they have then the survey will not be considered as available for selection and
the system will attempt to find another survey. After attempting to find another survey three times (this value is
configurable for On-Premise license holders) due to the fact that the respondent has already participated, the system
will stop trying to find a survey and will return nothing (as if no surveys are available for selection).
An exact match is required for all the criteria listed in the array. So in this case if a survey in the group does not have a
"gender" question, then that survey will not be considered for selection by the algorithm.

10.1.17.2. RedirectToRouterSurvey
RedirectToRouterSurvey is used to seamlessly route the respondent from one survey to another inside of the Survey
Router they are registered with.
RedirectToRouterSurvey(projectId, username, language{, fieldnames})

- 159 -
Forsta v2022 Scripting Manual Forsta Confidential

The survey ID that the respondent is to be routed to is supplied in the projectId (string), the unique identifier for the
respondent is supplied in the username (string), and the optional list of question IDs that are to be passed to the
routed-to survey is supplied in fieldNames (array of Strings). You can explicitly specify the language that the routed-to
survey is to use by supplying the optional language value. This is the numeric identifier for the “l” value. If no language
value is supplied, the survey default language will be used.
In the following example the respondent will be routed to the project ID stored in the question "targetSurvey" using the
unique identifier supplied in the question "uniqueID" and passing the values to questions "age", "gender" and "region".
var fieldNames : String[] = ["age", "gender", "region"]
RedirectToRouterSurvey(f("targetSurvey"), f("uniqueID"), fieldnames);
Open text, single choice and numeric questions can be passed to the target survey, other question types are not
supported. The questions that are passed can be normal, background or hidden, but no validation is performed on the
data until the question is executed in the target survey. If the question passed does not exist in the target survey no
error will be reported.
In this example, if the quota of the current project is filled then the respondent will automatically be routed to a new
project within their Survey Router group. Both age and gender questions will be passed to the target survey.

Note: Survey router redirection will only occur if the Survey Setting > Web Options > Survey type is set to
“Limited survey with external respondent creation” in the target survey.

Typically, you will not want to ask the same questions in the target survey as you have already asked in the initial
survey. To prevent this, a question mask can be applied to the questions that are passed to the target survey. In this
case you may check if the question has already been answered, and if so, do not display the question again:

Note: If you use this masking, remember to check the "No cleaning on question masking" property (refer to
the separate Survey Designer user guide for more information). If this property is not checked, then the data
will be cleared if the page is empty.

10.1.17.3. GetRouterName
GetRouterName()
The GetRouterName() function can be used to return the name of the router that the survey is assigned to. If the
survey is not assigned to a router, this function will return an empty string.

- 160 -
Forsta Confidential Forsta v2022 Scripting Manual

10.1.18. 3rd Party Integrations


Forsta incorporates a number of 3rd Party Software Components. Some of these components may allow or require
scripting to extract the full benefits of usage; these follow.

10.1.18.1. CintFulfillmentRespondentsTransition
The CintFulfillmentRespondentsTransition scripting function has the following signature:
CintFulfillmentRespondentsTransition(respondentId: String, status:
String)
Below are examples of how you might use the function to pass one of the three transition status values. Note that all
three are displayed together here; you would only ever use one at a time.

Note: This function requires that an administrator with the Company admin permission adds the Cint API key
to the Company Details page > Security tab. See the Forsta Administrator Manual for further details.

Code examples:
//Complete
SetStatus('complete')
SetInterviewEnd()
CintFulfillmentRespondentsTransition('04fe9a97-a579-43c5-bb1a-
58ed29bf0a6a', 'Complete')

//Screened
SetStatus('screened')
SetInterviewEnd()
CintFulfillmentRespondentsTransition('04fe9a97-a579-43c5-bb1a-
58ed29bf0a6a', 'Screenout')

//QuotaFull
SetStatus('quotafull')
SetInterviewEnd()
CintFulfillmentRespondentsTransition('04fe9a97-a579-43c5-bb1a-
58ed29bf0a6a', 'QuotaFull')

//QualityTerminate
SetStatus('screened')
SetInterviewEnd()
CintFulfillmentRespondentsTransition('04fe9a97-a579-43c5-bb1a-
58ed29bf0a6a', 'QualityTerminate')
The interview would be completed with the specified status and the respondent with the specified respondent GUID
will have the specified status passed over to Cint. Note that in these examples a GUID is hard-coded, however it could
reference a variable within the survey.

10.2. Creating Your Own Functions


You can create your own functions and use them where needed. It is recommended to use functions:

• Whenever there are pieces of code that it is likely that you will reuse several times in the questionnaire.
• When you need to refer to values (often computed expressions) that are not stored in survey variables.
• To group statements that perform a well-defined task, to make the code easier to read, and to make your code
more modularized.
Functions can be called from anywhere within the questionnaire.
Type annotation in a function specifies a required type for function arguments, a required type for returned data, or a
required type for both. If you do not type annotate the parameters of a function, the parameters will be of type Object.
Likewise, if the return type for a function is not specified, the compiler will infer the appropriate return type.

- 161 -
Forsta v2022 Scripting Manual Forsta Confidential

Using type annotation for function parameters helps ensure that a function will only accept data that it can process.
Declaring a return type explicitly for a function improves code readability since the type of data that the function will
return is immediately clear.

10.2.1. Defining functions


Before you can use a function, you must define it. In Forsta, functions are usually defined in script nodes. The syntax
of a function definition is as follows:
function FunctionName(p1 { : type},p2 { : type},...,pn { : type}) : type
{
<statements>
}
The function name is used to refer to the function in function calls. The same naming rules apply to function names as
to variable names. The convention for function names is to start them with a capital letter, to distinguish them from
variable names. The arguments (p1,p2,...) are the names of the variables that receive the values passed to the
function. You may define functions without any arguments at all, and functions with a variable number of arguments.
Type annotation on parameters and the function itself (for the return type) is not required.

10.2.2. Function Call


As we have seen in numerous examples, to call a function simply use the function name followed by parentheses
containing the arguments, if any:
FunctionName(p1,p2,...,pn)
A function defined in a survey's script node may be called in all script contexts; from other script nodes, conditions,
response piping (within ^s) and in code masks and column masks in the same survey.
The function RequiredMulti defined previously (see Defining functions on page 162 for more information) can be
called from the validation code of a multi question using:
RequiredMulti();

Note: When calling a function, ensure that you always include the parentheses and any required arguments.
Calling a function without parentheses causes the text of the function to be returned instead of the results of
the function.

10.2.3. Functions with a Fixed Number of Arguments


When you define a function with arguments, you define variables with the argument names as variable names. The
arguments will hold the values that are passed into the function, and may be used as normal JScript .NET variables
inside the function.

10.2.4. Functions with a Variable Number of Arguments


Previously in JScript you could define functions that took a variable number of arguments, using the arguments
array. In JScript .NET fast mode this is not available. If you need a function to take an arbitrary number of arguments,
you can use a parameter array. This is done by including, as the last element in the argument list, an array that is
defined with three periods (…), then the name of the array and then a typed array annotation:
function FunctionName(... parArray : type[]) { <statements> }
parArray can then be used like any other array inside the function.
parArray.length
returns the number of arguments in this array.
To refer to each argument in this array, use indexing as in all other arrays: 0 for the first argument, 1 for the second,
and so on:
parArray[index]
This makes it possible to write extremely flexible functions, as we have seen examples of in the built-in arithmetic
functions in Forsta; Sum, Count, Average, Max and Min (see Arithmetic Functions on page 72 for more information).

- 162 -
Forsta Confidential Forsta v2022 Scripting Manual

Code Masking Based on a Variable Number of Conditional Expressions


The following function can be used to create a code mask where the items to be included in the mask is determined
by the results from a number of conditional expressions that are sent in as parameters. It does require some caution
when used: It requires all answers to have numeric codes, and the position of the expression represents each code
(1,2,3,…).
function Pattern(... parArray : Object [])
{
__var codes = parArray.length;
__var s = new Set();
__for(var i: int = 0; i<codes; i++)
__{
____var code = i+1;
____var result = parArray[i];
____if(result==true)
____{
______s.add(code);
____}
__}
return s;
}
Here is an example of calling this function from a code mask:
Pattern(f("q1").toBoolean(),f("q2")=="2",f("q3").any("1","3","4"),true)
If q1 is answered, the answer with code 1 would be included. If the answer to q2 is "2", the answer with code 2 would
be included. If q3 (a multi) has answer(s) 1, 3 or 4, code 3 is included, and code 4 is always included.

Note: The script node defining this function must be placed before the question in which it is called in the
questionnaire tree.

10.2.5. The return Statement


Often you want a function to return a value, either a result from a calculation that has been done in the function, or just
a Boolean to indicate whether the function did what it was supposed to. To return a value to the statement that
invoked the function, use the return statement:
return expression
The return statement will terminate a possible loop and send the value to the statement that invoked the function.

Returning a Calculated Value from a Function


The following function will return what percentage the number n is out of the base b:
function Percentage(n : int,b : int) : float
{ return (n/b)*100; }

- 163 -
Forsta v2022 Scripting Manual Forsta Confidential

11. Objects
JScript .NET is an object-oriented language. We will not elaborate on the object-oriented features in this manual.
We will just describe the JScript and Forstaobjects that are relevant for survey programmers, and advice the reader to
consult a JScript .NET reference for more in-depth knowledge.
All script code in Forsta is wrapped as functions inside a class. This means that you can not define your own classes
in Forsta scripts.
JScript objects are collections of properties and methods. A method is a function that is a member of an object. A
property is a value or set of values that is a member of an object.

11.1. Properties
Properties are used to access the data values contained in an object.
An object's properties are accessed by combining the object's name and its property name:
objectName.propertyName
We have already seen an example of a property on the Array object, a property called length for the size of the
array (for example, the weekday array from previous examples):
weekday.length

11.2. Methods
Methods are functions that are used to perform operations on an object.
You access a method of an object by combining the object's name and the name of a method:
objectName.methodName(arguments)
Just like in functions, arguments in method calls are optional.
We have already used the basic variable objects of Forsta returned from the f function. We have seen some methods
that can be applied on these objects to retrieve information about the questions in a Forsta survey. For example will
f(qID).label()
return the title of the question with ID qID, and
f(qID).get()
the code or answer stored in the database for that question.
We have also seen a method that can be used to set the answer of a question:
f(qID).set(code)

11.3. Constructors: Creating Instances of Objects


Instances of objects of a particular object type are created using an operator called new, which you already have seen
used when creating an array, for example:
var a = new Array();
An array is a special object type. The general syntax for creating an instance of an object is like this:
variableName = new objectType(arguments);
objectType(arguments) is called the constructor of the object. Some object types have more than one
constructor. Constructors differ in the number of arguments they allow.

- 164 -
Forsta Confidential Forsta v2022 Scripting Manual

12. The f Function


The f function is probably the most important function available in Forsta. It is used to access survey
variables/questions, and we have already seen numerous examples of how to use it (see Methods of the Form
Objects on page 42 for more information).

12.1. Calling the f Function


f(qID,{loopiter1,loopiter2,...,loopitern})
returns a form object of some kind. A form is a question or loop node in a survey, and the argument qID is the
question ID as defined in the properties of the question.
The rest of the argument(s) (loopiter1,loopiter2,...,loopitern) are only used for questions inside loops.
These arguments are codes of specific loop iterations, starting with the innermost loop if there are nested loops (loops
within loops). The curly brackets {} are used here to indicate that the loop iterations are optional.
Let us say you have a question q1 in a nested loop structure with two loops. The outer loop has iterations with codes
"1" and "2", and the inner loop has iterations with codes "a" and "b". Then the question q1 is asked four times, and
these four instances of q1 can be referenced like this (in the order they were asked) from outside the loop:
f("q1","a","1")
f("q1","b","1")
f("q1","a","2")
f("q1","b","2")

12.2. Storing the Form Object in a Variable


The form objects can be large data structures with long answer lists and texts. Every call of the f function will result in
a new instance being retrieved. If the question has a code or scale mask, this mask will be evaluated for every call on
the f function for this question. It is recommended to try to reduce the number of calls on the f function, for example
by not always applying methods and properties directly on the function as we have been doing in all our examples so
far. If you will be calling the f function on the same question ID several times in a script (especially if you call the f
function inside a for or while loop), the best approach is to call it once and store the object instance in a variable
instead:
variableName = f(qID,{loopiter1,loopiter2,...,loopitern});
Usually the difference is not significant, but it is recommended because it will reduce the execution time of your
scripts. The interview pages will then load faster reducing the risk of irritating respondents and reducing server
performance.

12.3. Compounds
The f function returns in fact different objects for different question types. These objects have some properties and
methods in common, but some are specific to questions of a specific type.
Grid, multi, open text list, numeric list and ranking questions are questions with one or more variables that are defined
in the same form. They are called compounds. They can be accessed using the f function in the normal manner, but
the object returned is more complex than objects returned from other question types. You can refer directly to each of
their elements using syntax that is similar to that of an array:
x[code]
x represents a variable holding an instance of an object returned from calling the f function on a compound. code is
a string representing the code from the answer list of the compound. An example is referring to the element with code
"1" in a multi question with question ID q2:
f("q2")["1"]

Using a Variable instead of Repeated Calls on the f Function


Once more, back to the example with hours and weekdays where we validate the number of hours per day.

- 165 -
Forsta v2022 Scripting Manual Forsta Confidential

In our previous solution for validation of this question (see The while Statement on page 62 for more information) we
looped through the weekdays. For each day, we called the f function for three questions q2, q3 and q4:
sum = Sum(f("q2")[code],f("q3")[code],f("q4")[code]);
Now, instead we can define three variables sleep, work and leisure to hold the form objects:
var sleep = f("q2");
var work = f("q3");
var leisure = f("q4");
var codes = sleep.domainValues(); // array with all codes
var i : int = 0;
var correctSum : Boolean = true;
while(i<codes.length && correctSum) //iterate through codes (rows)
{
var code = codes[i]; //current code
//calculate sum:
var sum : int = Sum(sleep[code],work[code],leisure[code]);
if(sum != 24)
{
correctSum = false;
}
i++;
}
if(!correctSum)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please make sure that the total
number of hours for each day equals 24. Currently the sum for
"+sleep[code].label()+" is "+sum+".");
}

- 166 -
Forsta Confidential Forsta v2022 Scripting Manual

The way the script was initially set up you could have as much as 21 calls (3*7=21) on the f function inside the loop.
We have now reduced this to 3 function calls.

12.4. Properties
The form objects can have the following properties, depending on the type of the question (x represents a form object
returned from the f function):
x.CODED
CODED is true if the question referenced is a coded variable. If not, CODED is undefined. Coded variables are
single questions and loops, and answer list items of a grid or a multi question.
x.OPEN
OPEN is true if the question referenced is an open variable. If not, OPEN is undefined. Open variables are open text
questions, other-specify elements of answer lists and answer list elements of an open text list, numeric list or ranking
question.
x.DICHOTOMY
DICHOTOMY is true if the question referenced is a dichotomy. If not, DICHOTOMY is undefined. The elements of a
multi question (referenced with f(qID)[code]) are dichotomies.
x.COMPOUND
COMPOUND is true if the question referenced is a compound. If not, COMPOUND is undefined. Multi, open text list,
numeric list, ranking and grid questions are compounds.
x.NUMERIC
NUMERIC is true if the question referenced is numeric. If not, NUMERIC is undefined.
x.EXTERNAL
EXTERNAL is true if the question referenced gets its answerlist from Database Designer (either as a lookup table or a
hierarchy).
x.DATE
DATE is true if the question referenced is a date question. If not, DATE is undefined.
x.BOOL
BOOL is true if the question referenced is Boolean (has the Boolean property set). If not, BOOL is undefined.
x.GEO
GEO is true if the question referenced is a Geolocation question. If not, GEO is undefined.

Note: The Boolean property and Date question type are only available when using the Optimized database
format.

These properties are extremely powerful, because by using them it is possible to write generic scripts that will work no
matter what the question type is.
Using a combination of COMPOUND with DICHOTOMY and OPEN enables the user to differentiate between a grid
and a multi and a numeric list, open text list or ranking question since the elements of a multi are a DICHOTOMY, but
DICHOTOMY would be undefined for a grid, numeric list, open text list or ranking, and elements of numeric list, open
text list or ranking are OPEN, but OPEN is undefined for grid and multi.

- 167 -
Forsta v2022 Scripting Manual Forsta Confidential

var form = f("q1");


if(form.COMPOUND)
{
var cats = form.domainValues();
var code = cats[0];
if(form[code].DICHOTOMY)
{
//form is a multi
}
else if(form[code].OPEN)
{
//form is a numeric list, open text list or ranking question
}
else
{
//form is a grid
}
}

Deleting the Content of any Question


This function will remove the answers on any question, no matter what kind of question it is. This could for example be
used to automatically remove respondent information at the end of the survey if you ask the respondents if they want
to be anonymous or not. An answer is removed by overwriting the current value with null. It will work on open text,
single, date, numeric, multi, open text list, numeric list, ranking and grid questions, and you use it like this:
ClearForm(f("q1"));
for a question with question ID q1.
If the question is a compound, the function will remove answers in all variables in the compound. (It will however not
automatically remove a value in an "Other, specify" field on a question. To remove the answer on "Other, specify" you
have to call the function referring to the "Other, specify" field, e.g. like this:
ClearForm(f("q1_98_other"));
if the "Other " property is set on the item in the answer list with code "98".)
Here is the definition of the function:
function ClearForm(form)
{
if(form.COMPOUND) //form with multiple items
{
var fcodes = form.domainValues(); //all codes in form
for(var i : int = 0;i<fcodes.length;i++) //iterate through code
{
form[fcodes[i]].set(null); //clear item
}
}
else //form with one item
{
form.set(null);
}
}

Copying the Contents of any Form into Another


Here is a function that will copy any type of question. It will return true if the copying succeeds, and false without
copying anything if it does not. (If the from and to questions were not the same type of questions).

- 168 -
Forsta Confidential Forsta v2022 Scripting Manual

function CopyForm(from,to) : Boolean


{
if((from.CODED && to.CODED) || (from.OPEN && to.OPEN) ||
(from.DICHOTOMY && to.DICHOTOMY)|| (from.DATE && to.DATE) ||
(from.EXTERNAL && to.EXTERNAL))
{
to.set(from.get());
return true;
}
else if(from.COMPOUND && to.COMPOUND)
{
var fcodes = from.domainValues();
var tcodes = to.domainValues();
if(fcodes.length == tcodes.length)
{
for(var i : int = 0;i<fcodes.length;i++)
{
if(fcodes[i].toString()==tcodes[i].toString())
{
to[fcodes[i]].set(from[fcodes[i]].get());
}
else
{
return false;
}
}
return true;
}
}
return false;
}

12.5. The f Function Methods


The methods of the form objects are listed below. The methods are described in detail in sections Conversion
Methods in Forsta, Methods of the Form Objects, and Methods of the Set Object.

Methods CODED OPEN BOOL DATE NUMERIC DICHOTOMY COMPOUND GEO


toBoolean X X X X X X X X
toNumeric X X X X
toInt X X X X X
toDecimal X X X
toDate X
day X
month X
year X
datestring X
get X X X X X X X

set X X X X X X X
X

label X X X X X X X X
text X X X X X X X X
instruction X X X X X X X

- 169 -
Forsta v2022 Scripting Manual Forsta Confidential

value X X X X

valueLabel X X

domainValues X X X

domainLabels X X X

categories X

categoryLabels X

values X

getType X X X X X X X X
any X X
all X
none X X
between X
inc X X

size X X

union X X

isect X X

diff X X

members X X

isNearBy X
latitude X
longitude X

- 170 -
Forsta Confidential Forsta v2022 Scripting Manual

13. Working with Sets


Sets are typically used in code masks of single, multi, open text list, numeric list, ranking and grid questions, in loops,
and in scale masks of grids. A set consists of a collection of strings that represent codes. When used in code and
scale masks, the codes contained in the set are used to determine which answer alternatives are to be displayed to
the respondent. Only answers corresponding to codes from the set returned from the expression in the code or scale
mask will be shown.

13.1. Constructor
An instance of the Set object can be created like this:
s = new Set();
You will also get instances of the Set object returned from the functions a, set, nset, nnset, and Filter.

13.2. Functions Returning Sets


A number of functions return sets. These are described in the following sections.

13.2.1. The a Function


The function a returns a set consisting of all possible codes on a question (i.e. the codes of all items in the answer
list).
a(qID)

Note: There is a limitation with this function when qid uses a table lookup for its answerlist. In this case, it
should not be called from the code mask of qid. The workaround is to add an additional hidden single
question which points to the same table lookup, and use that with the a() call instead. So if qid1 uses table
lookup answerlist and needs to call a(qid1) in its code mask, instead it should use a(qid2) where qid2 is a
hidden single question that uses the same table lookup answerlist.

13.2.2. set, nset and nnset


There are three functions you can use to define sets with specific codes – set, nset and nnset.
set(code1,code2,...,coden)
will return a set consisting of the codes listed within the parenthesis. For example
set("1","3","4")
returns a set consisting of the codes "1","3" and "4".
nset(n)
will return a set with codes "1","2",...,n. n must be an integer greater than 0. For example
nset(5)
returns a set consisting of the codes "1","2","3","4" and "5".
nnset(m,n)
will return a set consisting of codes from m to n inclusive, i.e. m,m+1,...,n-1,n. For example
nnset(6,10)
returns a set consisting of the codes "6","7","8","9" and "10".

13.2.3. Iset
lset(params)
lset can be used to construct a set. The input to the function can either be an object such as an Array, or a list of
parameters from which the function will create a set.

- 171 -
Forsta v2022 Scripting Manual Forsta Confidential

lset(new Array(1,2,8))
returns a set consisting of the codes 1, 2 and 8.

13.2.4. The Filter Function


The function Filter is used to filter a list based on the matches a prefix has in the answer list.
Filter(qID,prefix)
It returns a set with the codes of items in the answer list of question qID that starts with the string prefix, regardless of
case. If prefix is "c", Filter will return the codes of the answers "Cadillac", "Chevrolet" and "Chrysler" if they are in the
answer list of qID.

Filtering an Answer List by the First Characters in the Answer


There may be situations where you have a single question with a long answer list, which you want to filter based on
text input by the respondents. In this case you can present an open text question to the respondents asking them to
provide the first one or two letters in their answer, and then filter the answer list based on that answer.
For example, imagine you have a single question carmake where the respondent is to be asked to select a car make
from a list. There are a lot of different car makes, so the selection list will be long. Here you can place an open text
question prefix in front of the car question. In the prefix question the respondent is asked to type in the first letter in the
name of the car, and this will filter the answer list such that only those car makes starting with the input letter will be
presented. The code mask of the car question can have this code mask:
Filter("carmake",f("prefix").get())

13.2.5. The f Function


The f function can also be used in set context (code and scale masks). The f function does not return a Set object,
but a form object. However, since it can be used in set context (in code and scale masks) and has most of the
methods of the Set object, we choose to discuss it together with the Set object. The two set methods not supported
by the form object, as indicated in the next section, are add and remove.
f(qID {,loopiter1,loopiter2,...,loopitern})
The curly brackets {} are used here to indicate that the loop iterations are optional arguments (see The f Function on
page 165 for more information).

13.3. Methods of the Set Object


In the syntax below, s1 and s2 represents instances of set objects or form objects (returned from the f function). For
add and remove s1 represents only an instance of the set object, because these methods are not defined for form
objects.

13.3.1. inc
s1.inc(code)
inc returns true if the code is contained in the set s1.
For example, for a multi question q1, the expression
f("q1").inc("1")
is true if the answer with code "1" has been selected on q1.
If you need an expression that is true if the answer with code "1" or the answer with code "2" has been selected, you
can use this code:
f("q1").inc("1") || f("q1").inc("2")
If you need an expression that is true if the answer with code "1" and the answer with code "2" has been selected,
you can use this code:
f("q1").inc("1") && f("q1").inc("2")

- 172 -
Forsta Confidential Forsta v2022 Scripting Manual

13.3.2. size
s1.size()
size returns the number of elements in the set s1.

Asking for Favorite Only when More than 1 Item is Chosen


If you have a multi question cars asking for cars the respondent would like to drive, followed by a single question
cars_favorite asking for the favorite among those selected in cars, the single question is only needed when more than
1 element is chosen on the multi. This can be achieved with the following expression in a condition:
f("cars").size()>1
The cars favorite question will then have the following code mask so that it only shows answers from the cars
question::
f("cars")

13.3.3. union, isect and diff


There are three methods available to use for set operations: union, isect and diff. These methods are useful
when you need complex code masks, for example when you want to filter the answer list based on answers to two
previous questions. Examples of this are: Showing the items answered on both questions, on any of the questions, on
one but not the other etc.
s1.union(s2)
The union of two sets s1 and s2 is the set obtained by combining the members of both sets. So union will return a set
consisting of all elements in s1 or s2.

s1.union(s2)

s1.isect(s2)
The intersection of two sets s1 and s2 is the set of elements common to s1 and s2. So isect will return a set
consisting of the elements that are both in s1 and s2.

- 173 -
Forsta v2022 Scripting Manual Forsta Confidential

s1.isect(s2)

s1.diff(s2)
The difference between two sets s1 and s2 will yield a set consisting of the elements that are in the first set, but not in
the other. For difference the order of the sets in the expression is significant. s1.diff(s2) will return a set consisting
of the elements in s1 that are not in s2, but s2.diff(s1) will return a set consisting of the elements in s2 that are not
in s1. As the illustrations show, these are two completely different sets.

- 174 -
Forsta Confidential Forsta v2022 Scripting Manual

s1.diff(s2)

s2.diff(s1)

Filtering an Answer List on Items Selected in Two Previous Questions


You have two multi questions q1 and q2, and then a loop where you loop through the same answer list that is used in
q1 and q2.
If you want the loop to be filtered so that only the items the respondent answered in both q1 and q2, you can use a
code mask like this on the loop:
f("q1").isect(f("q2"))
If you want the loop to be filtered so that all the items the respondent answered in either of q1 or q2, you can use a
code mask like this on the loop:
f("q1").union(f("q2"))
If you want the loop to be filtered so that only items answered in q1, but not in q2, you can use a code mask like this:
f("q1").diff(f("q2"))
Similar, for items answered in q2 but not in q1:
f("q2").diff(f("q1"))

Filtering Answers Not Selected in a Previous Question


If you have a multi question q1 followed by a grid q2 where you only want the answers not selected in q1 to be
displayed, you can use the a function to get a set with all the codes in the answer list, and use the diff method to
remove the codes of the answers selected on q1. The code for such a code mask will be like this:
a("q2").diff(f("q1"))

- 175 -
Forsta v2022 Scripting Manual Forsta Confidential

You have to use the same codes for corresponding items in the answer lists of the two questions. This can easily be
achieved for example by using a predefined list.

Always Including a "Don't know" Answer Alternative


Often you want to filter the answer list, but you want a "Don't know" alternative always to be included at the bottom of
the answer list. Say for example a multi q1 is followed by a single question q3 where the answers given to q1 and
"Don't know" should be displayed. It is a good idea to assign a code to "Don't know" that is different from the other
codes, for example by using a large number like "99" or letters like "DK". We will use "DK" in this example. In the code
mask of q3 we can use this code:
f("q1").union(set("DK"))

13.3.4. Combining Set Operators


You may build expressions where several set operators are combined. When several set operators are included in the
same expression, the expression is evaluated from left to right. So if you for example have three sets s1, s2 and s3,
the expression
s1.isect(s2).union(s3)
will give a set consisting of all codes either in the sets s1 and s2, or in set s3:

s1.isect(s2).union(s3)

To force a sub-expression to be evaluated before other expressions, you can insert entire expressions inside the
parentheses of the set methods. In the expression
s1.isect(s2.union(s3))
the sub-expression s2.union(s3) will be evaluated first, and then the intersection between the result of this sub-
expression and the set s1 is computed. The result is a set consisting of all codes both in s1and in either of s2 or s3:

- 176 -
Forsta Confidential Forsta v2022 Scripting Manual

s1.isect(s2.union(s3))

Exercise 6:
You have three sets: s1, s2 and s3. s1 consists of the codes 1,2,5,7,10,11, s2 consists of the codes
3,4,5,8,11,13 and s3 consists of the codes 2,4,5,6,9,10,12, as indicated in the illustration above.

- 177 -
Forsta v2022 Scripting Manual Forsta Confidential

What elements will the sets returned from the following expressions contain?

1. s1.union(s3.diff(s2))
2. s1.union(s3).diff(s2)
3. s1.isect(s2.diff(s3))
4. s1.isect(s2).union(s2.isect(s3)).union(s3.isect(s1))
The answers are given in APPENDIX A Answers to Exercises.

13.3.5. members
s1.members()
members is used to convert a set to an array.

Validating "Other, specify" in a 3D Grid


For grids/singles/multiples it is possible to automatically validate Other-specify by checking the "Other - Specify
checking..." setting in Project Management > Survey Settings > Validation & XSS tab:

However this setting does not apply to 3D grids since Forsta cannot deduce which question within a 3D grid should be
validated with the Other-specify; instead it is necessary to use some manual validation code.
The question ID to refer to an Other-specify within a 3D grid is:
3d-grid-id_code_other
For example, we have a 3D grid (g1) containing a multi (q1) and a rating grid (q2); the 3d grid has answers/codes 1-4
with the 4th code being an Other specify.

We wish to validate so that the respondent is forced to add Other-specify text if they select this option in the multi q1.
The validation code for this is:

- 178 -
Forsta Confidential Forsta v2022 Scripting Manual

var codes = a("q1").diff(set("97","98")).members();


if(f('q1').inc('4') && !f('g1_4_other').toBoolean() )
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please specify in the Other Specify
box");
}
if(!f('q1').inc('4') && f('g1_4_other').toBoolean())
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please do not specify in the Other
Specify box without selecting this answer");
}

13.3.6. add and remove


To add and remove items from a set, there are two methods available: add and remove.
s1.add(code);s1.remove(code);
add will add code to the set s1. If code is already in the set s1, the set will not be changed. remove will remove code
from the set s1. If code is not in the set s1, the set will not be changed.
These methods are not defined for the form objects (returned from the f function), only for the set object.

Using a Function to Filter an Answer List Based on the Answers on a Grid


If you have a grid where you give some elements a rating from 1-5, you may for example want the next question to
use only the elements that get a score of 4 or 5. This can be achieved with a function like this defined in a script node:
function ScoreFilter(qID)
{
var form = f(qID);
var codes = form.domainValues();
var s = new Set();
var i : int;
for(i=0;i<codes.length;i++)
{
var code = codes[i];
if(form[code].get() == "4" || form[code].get() == "5")
{
s.add(code);
}
}
return s;
}
This function returns a set with the codes of the items that have received a score of "4" or "5". In the code mask where
you want to use it , call this function with the question ID of the grid (for example q3) as argument:
ScoreFilter("q3")

Note: If the respondent does not score any grid elements “4” or “5”, then ScoreFilter() will return an empty
set/mask and the respondent will be presented with an empty question (since all answers are masked out). It
would therefore be reasonable to also include a question mask (or condition node):
ScoreFilter("q3").size()>0
Then, if the question is ‘empty’, it will be skipped.

13.3.7. .any, .all and .none


These methods can be used to check whether a set includes specific codes:
s1.any(code1,code2,…,coden);
s1.all(code1,code2,…,coden);
s1.none(code1,code2,…,coden);

- 179 -
Forsta v2022 Scripting Manual Forsta Confidential

any will return true if any of the codes listed can be found in the set s1.
all will return true if all of the codes listed can be found in the set s1.
none will return true if none of the codes listed can be found in the set s1.

13.4. User-Defined Functions in Code or Scale Masks


The previous example used a user-defined function in the code mask field. This is a convenient way of doing it, but
there are a few pitfalls with this approach.
The code mask is called several times when you go through the questionnaire, not only when the question is
displayed. Every time you use the f function on a question with a code mask, the code mask is evaluated. So the
function in the code mask of a question will be called every time there is a reference to the question in scripts
elsewhere in the survey.
Due to this, the time it takes for the respondent to load the survey pages will increase slightly because there are more
scripts to execute.
You are therefore recommended to be cautious when using functions in code masks. An alternative approach is to set
a hidden multi question and filter on that instead. This hidden multi question can also be useful for reporting purposes.

Using a Hidden Multi to Filter an Answer List Based on a Grid


As described previously (see add and remove on page 179 for more information), we have a grid where the elements
are given a 1-5 rating, and we want the next question to use only the elements that are given a score of "4" or "5".
Now let us use a script to set a hidden multi question, scorefilter, instead of using a function. The grid has question ID
carrating.
var form = f("carrating");
var codes = form.domainValues();
var i : int;
for(i=0;i<codes.length;i++)
{
var code = codes[i];
if(form[code].get() == "4" || form[code].get() == "5")
{
f("scorefilter")[code].set("1");
}
else
{
f("scorefilter")[code].set("0");
}
}
Then the code mask uses scorefilter instead of the function call:
f("scorefilter")

- 180 -
Forsta Confidential Forsta v2022 Scripting Manual

14. Some Useful JScript .NET Objects


This chapter describes some of the objects provided in JScript .NET. The objects that are most useful for scripting in
Forsta, and the properties and methods that are most frequently used, are presented. For descriptions of other JScript
.NET Objects, consult a JScript .NET reference manual.

14.1. The Date Object


The Date object enables basic storage and retrieval of dates and times, and can be used to set timestamps, do
calculations of time differences and to validate dates in the respondent's answers.
The Date object type of JScript .NET provides a common set of methods for working with dates and times, either the
Local Time or Universal Coordinated Time (UTC). Since we are working with scripts that run on the Forsta servers
(server-side), not on the respondent's PC (client-side), Local Time means the time on the Forsta servers you are
working on. Universal Coordinated Time (UTC) (sometimes also called "Zulu Time") was formerly called Greenwich
Mean Time (GMT) and is the mean solar time at the prime meridian (0° longitude).
Date values are stored internally as the number of milliseconds since January 1, 1970 UTC. For dates before this
date, this will be a negative number. The range of dates that can be represented in an instance of the Date object is
approximately 285,616 years on either side of January 1, 1970. This should be sufficient for most of us.

14.1.1. Constructors
You can create a new instance of the Date object in three ways:
dateObj = new Date();
dateObj = new Date(dateVal);
dateObj = new Date(year, month, date{, hours{, minutes{,
seconds{,ms}}}});
If you just use the constructor Date(), the instance of the Date object will be set to current date and time.
If you use Date(dateVal) and dateVal is an integer, dateVal represents the number of milliseconds since
midnight January 1, 1970 Universal Coordinated Time. Negative numbers indicate dates prior to 1970. If dateVal is
a string, dateVal is parsed according to the rules in the parse method (see parse on page 182 for more
information)).
Here are two ways of getting an instance of the Date Object that is set to midnight 2000 (UTC):
d = new Date(946684800000);
d = new Date("Sat, 1 Jan 2000 00:00:00 UTC");
When you use Date(year,month,date{,hours{,minutes{,seconds{,ms}}}}), the first three arguments are
required. year has to be the full year, for example 1984 (and not just 84). month is an integer between 0 and 11
(This means that January is 0, December is 11. This is similar to how we have seen that arrays are indexed, where 0
is the first element). date is an integer between 1 and 31.
The next arguments are optional (that's what the curly brackets indicate), but when one of them is included, all
preceding arguments must be supplied. This means that if you specify seconds, it has to be preceded by hours and
minutes. hour is an integer from 0 to 23 (midnight to 11pm). minutes and seconds are integers from 0 to 59 and
milliseconds is an integer from 0 to 999. Here is an example:
d = new Date(2000,0,1,0,0,0,0);
This may or may not be equal to the two examples above using the other constructors. It depends on the server
settings on the Forsta server. The two examples above both use UTC. With this last constructor, the time zone cannot
be specified. The time zone of the Forsta server will be used.
If an argument is greater than its range or is a negative number, other stored values are modified accordingly. So 150
seconds will be redefined as 2 minutes and 30 seconds. The 2 minutes will be added to the minutes value. If this
exceeds 60 minutes, hours will be modified and so on.

- 181 -
Forsta v2022 Scripting Manual Forsta Confidential

14.1.2. Date Object Methods


The Date object has two static methods. They are called static because they are called without creating an instance
of the Date object. They are parse and UTC. The other methods are invoked as methods of a created instance of
the Date object. In code below dateObj is an instance of a Date object.

14.1.2.1. Static Methods


14.1.2.1.1. parse
Parses a string containing a date, and returns the number of milliseconds between that date and midnight, January 1,
1970.
Date.parse(dateVal)
dateVal is a string containing a date.
The parse method returns an integer value representing the number of milliseconds between midnight, January 1,
1970 and the date supplied in dateVal.
The parse method is a static method of the Date object. Because it is a static method, it is invoked as shown in the
following example, rather than invoked as a method of a created Date object.
Date.parse("January 1, 2000 00:00 AM")
The following rules govern what the parse method can successfully parse:

• Short dates can use either a "/" or "-" date separator, but must follow the month/day/year format, for example
"7/20/96".
• Long dates of the form "July 10 1995" can be given with the year, month, and day in any order, and the year in
2-digit or 4-digit form. If you use the 2-digit form, the year must be greater than or equal to 70.
• Any text inside parentheses is treated as a comment. These parentheses may be nested.
• Both commas and spaces are treated as delimiters. Multiple delimiters are permitted.
• Month and day names must have two or more characters. Two character names that are not unique are
resolved as the last match. For example, "Ju" is resolved as July, not June.
• The stated day of the week is ignored if it is incorrect given the remainder of the supplied date. For example,
"Tuesday November 9 1996" is accepted and parsed even though that date actually falls on a Friday. The
resulting Date object contains "Friday November 9 1996".
• JScript .NET handles all standard time zones, as well as Universal Coordinated Time (UTC) and Greenwich
Mean Time (GMT).
• Hours, minutes, and seconds are separated by colons, although all need not be specified. "10:", "10:11", and
"10:11:12" are all valid.
• If the 24-hour clock is used, it is an error to specify "PM" for times later than 12 noon. For example, "23:15 PM"
is an error.
• A string containing an invalid date is an error. For example, a string containing two years or two months is an
error.

14.1.2.1.2. UTC
UTC returns the number of milliseconds between midnight, January 1, 1970 Universal Coordinated Time (UTC) (or
GMT) and the supplied date.
Date.UTC(year, month, day{, hours{, minutes{, seconds{,ms}}}})
The arguments are equal to those of the Date(year,month,day{,hours{,minutes{,seconds{,ms}}}})
constructor (see Constructors on page 181 for more information).
If the value of an argument is greater than its range, or is a negative number, other stored values are modified
accordingly. For example, if you specify 150 seconds, JScript .NET redefines that number as two minutes and 30
seconds.

- 182 -
Forsta Confidential Forsta v2022 Scripting Manual

The difference between the UTC method and the corresponding Date object constructor is that the UTC method
assumes UTC, and the Date object constructor assumes local time. (Local time when doing server side scripting will
be the time zone of the Forsta servers, not the time zone of the client (the PC of the respondent)).
The UTC method is a static method. Therefore, a Date object does not have to be created before it can be used.
Date.UTC(2000,0,1,0,0,0,0)

14.1.2.2. Methods for Setting or Retrieving Values of Parts of Dates


The methods with UTC in the method name use Universal Coordinated Time. The other methods use local time, and
as we are dealing with server-side scripts that will be the time of the Forsta server. The following table show these
methods grouped based on the date part they operate on. Curly brackets, { and }, are used to indicate optional
arguments.

getFullYear() getUTCFullY setFullYear(numYear{, numMonth{, setUTCFullYear(numYear{, numMonth{,


ear() numDate}}) numDate}})
getMonth() getUTCMont setMonth(numMonth{, numDate}) setUTCMonth(numMonth{, numDate})
h()
getDay() getUTCDay()
getDate() getUTCDate( setDate(numDate) setUTCDate(numDate)
)
getHours() getUTCHours setHours(numHours{, numMinutes{, setUTCHours(numHours{, numMinutes{,
() numSeconds{, numMilliseconds}}}) numSeconds{, numMilliseconds}}})
getMinutes() getUTCMinut setMinutes(numMinutes{, setUTCMinutes(numMinutes{, numSeconds{,
es() numSeconds{, numMilliseconds}}) numMilliseconds}})
getSeconds( getUTCSeco setSeconds(numSeconds{, setUTCSeconds(numSeconds{,
) nds() numMilliseconds}} numMilliseconds})
getMillisecon getUTCMillis setMilliseconds(numMilliseconds) setUTCMilliseconds(numMilliseconds)
ds() econds()
getTime() setTime(milliseconds)
getTimezone
Offset()

For the methods that set date parts, the other parts of the date are modified accordingly if the value of an argument is
greater than its range or is a negative number. So, if you for example use the setMinutes method with 62 as
argument, minutes will be set to 2 and hours will be increased with 1. If this makes hours exceed its limit, date is
changed to the next day, and so on. This gives a very efficient way of working with dates in scripts.
For all methods with numMonth as argument, remember that JScript .NET months use the numbers 0 to 11. 0 is
January and 11 is December.

14.1.2.2.1. getFullYear, getUTCFullYear, setFullYear and setUTCFullYear


dateObj.getFullYear()
dateObj.getUTCFullYear()
getFullYear and getUTCFullYear return the year value in the Date object as an absolute number, thus avoiding
the Y2K problem.
dateObj.setFullYear(numYear{, numMonth{, numDate}})
dateObj.setUTCFullYear(numYear{, numMonth{, numDate}})
setFullYear and setUTCFullYear set the year value in the Date object.
numYear is required and is a numeric value equal to the year.

- 183 -
Forsta v2022 Scripting Manual Forsta Confidential

numMonth and numDate are both optional. If numDate is supplied, numMonth must also be supplied. numMonth is a
numeric value equal to the month (0-11). numDate is a numeric value equal to the date (1-31).
If you do not specify the optional arguments, the value will be retrieved from the corresponding get method. For
example, if numMonth is not specified, JScript .NET uses the value returned from the getMonth or getUTCMonth
method.
If the value of an argument is greater than its range or is a negative number, other stored values are modified
accordingly.
There are two methods called getYear and setYear. They are obsolete and kept for backwards compability only. It
is not recommended to use them, because of Y2K problems. Use the FullYear methods instead.

14.1.2.2.2. getMonth, getUTCMonth, setMonth and setUTCMonth


dateObj.getMonth()
dateObj.getUTCMonth()
getMonth and getUTCMonth return the month value in the Date object. The value returned is an integer between 0
and 11 indicating the month value in the Date object. Note that this is different from the conventional way of
numbering months (1-12). The numeric value for January is 0 and for December the value is 11, one less than the
usual way of numbering the months. If "Jan 1, 2000 00:00:00" is stored in a Date object, getMonth returns 0.
dateObj.setMonth(numMonth{, dateVal}) dateObj.setUTCMonth(numMonth{,
dateVal})
setMonth and setUTCMonth set the month value in the Date object. numMonth is required, and is a numeric value
equal to the month (0-11).
dateVal is optional. It is a numeric value representing the date. If not supplied, the value from a call to the getDate
or getUTCDate method is used.
If the value of numMonth is greater than 11 or is a negative number, the stored year is modified accordingly. For
example, if the stored date is "Jan 1, 2000" and setMonth(14) is called, the date is changed to "Mar 1, 2001."

14.1.2.2.3. getDay and getUTCDay


dateObj.getDay()
dateObj.getUTCDay()
getDay and getUTCDay return the day of the week of the Date object.
The value returned from the getDay method is an integer between 0 and 6 representing the day of the week and
corresponds to a day of the week as follows:

Value Day of the Week

0
Sunday

1
Monday

2
Tuesday

3
Wednesday

4
Thursday

5
Friday

- 184 -
Forsta Confidential Forsta v2022 Scripting Manual

6
Saturday

14.1.2.2.4. getDate, getUTCDate, setDate and setUTCDate


dateObj.getDate()
dateObj.getUTCDate()
getDate and getUTCDate return the day of the month value in a Date object. The return value is an integer
between 1 and 31 that represents the date value in the Date object.
dateObj.setDate(numDate)dateObj.setUTCDate(numDate)
setDate and setUTCDate set the day of month value of the Date object.
numDate is a numeric value equal to the day of month value. If the value is outside the number of days in the month
stored in the Date object or a negative number, the other values are modified accordingly, e.g. so that if the date of
the object is January 1st 2000 and you use setUTCDate(32) on that object, you get February 1st 2000.

14.1.2.2.5. getHours, getUTCHours, setHours and setUTCHours


dateObj.getHours()
dateObj.getUTCHours()
getHours and getUTCHours return the hours value in a Date object.
The value returned is an integer between 0 and 23, indicating the number of hours since midnight.
dateObj.setHours(numHours{, numMin{, numSec{,
numMilli}}})dateObj.setUTCHours(numHours{, numMin{, numSec{, numMilli}}})
setHours and setUTCHours set the hours value in a Date object.
The only required argument is numHours, which is a numeric value equal to the hours value.
The rest of the arguments are optional. If they are not included, the results from using the corresponding get functions
are used. For example, if numMin is not provided, the result from getMinutes or getUTCMinutes is used. All
preceding arguments must be included if one of the optional arguments is included. For example, if numSec is used,
numMin must also be included in the method call.
numMin is a numeric value equal to the minutes value, numSec is a numeric value equal to the seconds value and
numMilli is a numeric value equal to the milliseconds value.
If the value of an argument is greater than its range or is a negative number, other stored values are modified
accordingly. For example, if the stored date is "Jan 1, 2000 00:00:00", and setHours(30) is called, the date is
changed to "Jan 2, 2000 06:00:00." Negative numbers have a similar behavior.

14.1.2.2.6. getMinutes, getUTCMinutes, setMinutes and setUTCMinutes


dateObj.getMinutes()
dateObj.getUTCMinutes()
getMinutes and getUTCMinutes return the minutes value in a Date object.
The value returned is an integer between 0 and 59 equal to the minutes value stored in the Date object.
dateObj.setMinutes(numMin{, numSec{,
numMilli}})dateObj.setUTCMinutes(numMin{, numSec{, numMilli}})
setMinutes and setUTCMinutes set the minutes value in a Date object.
The only required argument is numMinutes, which is a numeric value equal to the minutes value.

- 185 -
Forsta v2022 Scripting Manual Forsta Confidential

The rest of the arguments are optional. If they are not included, the results from using the corresponding get functions
are used. For example, if numSec is not provided, the result from getSeconds or getUTCSeconds is used. All the
preceding arguments must be included if one of the optional arguments is included. If numMilli is used, numSec
must also be included in the method call.
numSec is a numeric value equal to the seconds value and numMilli is a numeric value equal to the milliseconds
value.
If the value of an argument is greater than its range or is a negative number, other stored values are modified
accordingly. For example, if the stored date is "Jan 1, 2000 00:00:00", and setMinutes(62) is called, the date is
changed to "Jan 1, 2000 01:02:00." Negative numbers have a similar behavior.

14.1.2.2.7. getSeconds, getUTCSeconds, setSeconds and setUTCSeconds


dateObj.getSeconds()
dateObj.getUTCSeconds()
getSeconds and getUTCSeconds return the seconds value in a Date object.
The value returned is an integer between 0 and 59 equal to the seconds value stored in the Date object.
dateObj.setSeconds(numSeconds{,
numMilli})dateObj.setUTCSeconds(numSeconds{, numMilli})
setSeconds and setUTCSeconds set the seconds value in a Date object.
The only required argument is numSeconds, which is a numeric value equal to the seconds value.
numMilli is optional. If it is not included, the results from using the corresponding get functions are used
(getMillieconds or getUTCMilliseconds).
numMilli is a numeric value equal to the milliseconds value.
If the value of an argument is greater than its range or is a negative number, other stored values are modified
accordingly. For example, if the stored date is "Jan 1, 2000 00:00:00", and setSeconds(124) is called, the date is
changed to "Jan 1, 2000 00:02:04." Negative numbers have a similar behavior.

14.1.2.2.8. getMilliseconds, getUTCMilliseconds, setMilliseconds and setUTCMilliseconds


dateObj.getMilliseconds()
dateObj.getUTCMilliseconds()
getMilliseconds and getUTCMilliseconds return the milliseconds value in a Date object.
The millisecond value is an integer from 0 to 999.
dateObj.setMilliseconds(numMilli) dateObj.setUTCMilliseconds(numMilli)
setMilliseconds and setUTCMilliseconds set the milliseconds value in the Date object.
numMilli is a numeric value equal to the milliseconds value.
If the value of numMilli is greater than 999 or is a negative number, the stored number of seconds (and minutes,
hours, and so forth if necessary) is modified accordingly.

14.1.2.2.9. getTime and setTime


dateObj.getTime()
getTime returns an integer value representing the number of milliseconds between midnight, January 1, 1970 UTC
and the time value in the Date object. Negative numbers indicate dates prior to 1970.
dateObj.setTime(milliseconds)
setTime sets the date and time of the instance of the Date object. milliseconds is an integer value representing
the number of elapsed seconds since midnight, January 1, 1970 UTC. If milliseconds is negative, it indicates a
date before 1970.

- 186 -
Forsta Confidential Forsta v2022 Scripting Manual

14.1.2.2.10. getTimezoneOffset
dateObj.getTimezoneOffset()
Returns the difference in minutes between the time on the host computer (the Forsta server when doing server-side
scripting) and Universal Coordinated Time (UTC). This number will be positive if you are behind UTC (e.g., Pacific
Daylight Time), and negative if you are ahead of UTC (e.g., Japan).

14.1.2.3. Date Conversion Methods


Two conversion methods are available for dates.

14.1.2.3.1. valueOf
dateObj.valueOf()
valueOf returns the stored time value in milliseconds since midnight, January 1, 1970 UTC.

14.1.2.3.2. toLocaleString, toString and toUTCString


dateObj.toLocaleString()
toLocaleString returns a date converted to a string using the current locale. This mean that it will give the Forsta
server time, and the date is formatted according to the Regional Settings on the server.
dateObj.toUTCString()
toUTCString returns a string that contains the date formatted using Universal Coordinated Time (UTC) convention.
dateObj.toString()
toString returns the textual representation of the date, in the time of the Forsta server, but not reflecting the locale
settings.
Here is an example of the output from the three different methods from a server with English (United States) as locale
and where the time zone is EST (such as Forsta's Forsta ASP servers):

Method Output

toUTCString
Sat, 1 Jan 2000 00:00:00 UTC

toLocalString
Friday, December 31, 1999 7:00:00
PM

toString
Fri Dec 31 19:00:00 EST 1999

There also exists a method called toGMTString, which returns a date converted to a string using Greenwich Mean
Time(GMT). This method is obsolete, and it is recommended that you use the toUTCString method instead.

14.1.3. Date Functions and Date Questions


Forsta provides six functions for working with dates. InterviewStart and InterviewEnd return the
interview_start and interview_end time stamps automatically recorded when the respondent starts the interview and
reach the end of the interview or a stop node (the end page). SetInterviewStart and SetInterviewEnd set
these timestamps. IsDate and IsDateFmt are used for validation of dates.
Such date variables can be used both in the surveys when asking respondents for dates (for examples date of birth),
and also as "hidden" variables to set and store dates through scripting. The date question type has built in validation
and a calendar pop-up interface, so it is not necessary to use the IsDate and IsDateFmt functions for validation of the
respondent's answer when using this question type.

- 187 -
Forsta v2022 Scripting Manual Forsta Confidential

14.1.3.1. InterviewStart and InterviewEnd


Both of these functions return dates, however they will return the dates as strings. The syntax you can use to get
instances of the JScript .NET Date object from InterviewStart and InterviewEnd is as below:
dateObj = InterviewStart();
dateObj = InterviewEnd();

Calculating Time Spent


You can calculate the response time of the respondents on specific pages or sections of the survey by using the Date
object. Assume you want to calculate the number of seconds the respondent has spent from the beginning to a
specific point in the interview and store that in a numeric question with hidden property (time_part1).
if(!f("time_part1").toBoolean())
{
var d1 = InterviewStart()
var d2 = new Date()

var diff = (d2.getTime() - d1.getTime())/1000


f("time_part1").set(diff)
}
The if-condition is there to ensure that the time is only calculated the first time the respondent goes through the
questionnaire (if he or she is allowed to modify previous responses), when no value has been set in the hidden
time_part1 question.
You must ensure you use the correct settings on the hidden numeric question. Decimal places should be set to 3 (3
digits after the decimal point) since getTime returns milliseconds. We divide the number of milliseconds with 1000 to
get the answer stored as seconds. Total digits has to be set high enough to be able to store both the 3 digits after the
decimal point and the highest number of seconds a respondent will use.
If you want to calculate the response time for the next part of the questionnaire as well, you can for example use the
following script to set that in another hidden numeric question (time_part2):
if(!f("time_part2").toBoolean())
{
var d1 = InterviewStart();
var d2 = new Date();

var diff = ((d2.getTime() - d1.getTime())/1000)-


f("time_part1").toNumber();
f("time_part2").set(diff);
}

14.1.3.2. IsDateFmt and IsDate


These functions are also described in IsDateFmtAndIsDate. Here we will look closer at the properties of the objects
returned from them and provide some examples on how to use the functions together with the JScript Date object.
If you have a string with day, month and year in some format (for example from an open text question) and you want
to check if it is a valid date, you can use the IsDateFmt function.
dObj = IsDateFmt( argument,format );
If you have three values, one for day, one for month and one for year, (for example from three questions), you can use
IsDate to check if it is a valid date.
dObj = IsDate( day,month,year );
Both IsDateFmt and IsDate return an object with the properties day, month and year if the date is valid, null
otherwise. The object returned is not a Date object – it has none of the methods of the Date object, just these three
properties.
dObj.day
returns the day part of the date as an integer in the range 1-31.
dObj.month

- 188 -
Forsta Confidential Forsta v2022 Scripting Manual

returns the month part of the date as an integer in the range 1-12.

Important:
Note that this is different from the Date object, where getMonth and getUTCMonth return an integer in the
range 0-11.

dObj.year
returns the year part of the date as an integer (4 digits).
In this example we have an open text question and want the respondent to enter a date in the format YYYY-MM-DD.
We want to validate that the format is correct and that the date is a valid date, and also that the date is not after the
current date.
This can be done with the following script in the validation code field of the open text question (date1).
var d = IsDateFmt(f("date1").get(),"YYYY-MM-DD");

if(!d)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Invalid date. Please correct using
the format YYYY-MM-DD");
}
else
{
var dt = new Date();
dt.setFullYear(d.year,d.month-1,d.day);
var current = new Date();
if(dt.valueOf() > current.valueOf())
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please do not enter a date after
the current date.");
}
}
If the date provided is not valid, IsDateFmt(f("date1").get(),"YYYY-MM-DD") will return null. Used in a
condition null will yield the Boolean value false. If the date is valid, IsDateFmt will return an object. Used in a
condition this will yield true. So the first if condition, with !d , makes sure there will come an error message only
when the date is invalid or wrong format is used.
It is important that we include the rest of the script in an else branch because the properties year, month and day
are not defined if null is returned. So we need to make sure that that part of the script only is run when we have an
object in the variable d, to prevent script errors.
Then we introduce two instances of the Date object, and set one of them (dt) to the date answered, and the other
(current) to the current date. We use the setFullYear method to set the date. Observe that we have to subtract 1
from the month, since the Date object uses the integers 0-11 for month, whereas the month property in the object
returned from IsDateFmt uses the more conventional integers 1-12.

Validating that a Date with Drop-downs is within the next two Weeks
You can also set up the date with three questions, one for year, one for month and one for day. This can for example
be set up in a 3D grid with 3 grid questions as drop-downs like this:

- 189 -
Forsta v2022 Scripting Manual Forsta Confidential

Note: The codes of the questions must be numeric and the same as the legal year/month/day values. For
year the codes must be the full value (e.g. 2002), for month they must be numbers between 1 and 12, and for
day they must be numbers between 1 and 31 (see IsDateFmt and IsDate on page 146 for more information).

Let us say that we want to check that the answer is a valid date (so that e.g. February 30 th is not allowed), and that it
is a date in the next two weeks from the current date.
var d =
IsDate(f("day")["1"].get(),f("month")["1"].get(),f("year")["1"].get());

if(!d)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Invalid date. Please correct.");
}
else
{
var dt = new Date();
dt.setFullYear
(d.year,d.month-1,d.day);
var current = new Date();
var limit = new Date();
limit.setDate(current.getDate()+14)
if(dt.valueOf() < current.valueOf() || dt.valueOf() > limit.valueOf())
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please select a date within the
next two weeks.");
}
}

- 190 -
Forsta Confidential Forsta v2022 Scripting Manual

This script takes advantage of the fact that when using setDate, the month and possibly also year value will
automatically be updated if the value for date is outside the limit for the month. So if the result of
current.getDate()+14 is a number larger than the number of days in a month, limit will be set to a date in the
next month. For example, if current date is April 20th 2002, the limit will be 4th of May 2002 (April 20th + 14 days).

Finding the Weekday


You can use the Date object to make a small application in Forsta to find the weekday of a specific date. Start with an
open text question (date3) asking for a date. The validation can be done like this:
var d = IsDateFmt(f("date3").get(),"YYYY-MM-DD");
if(!d)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Invalid date. Please correct. Use
the format YYYY-MM-DD");
}
Then you can have a script node with the following function:
function FindDay(qID) : String
{
var d = IsDateFmt(f(qID).get(),"YYYY-MM-DD");
var dt = new Date();
dt.setFullYear(d.year,d.month-1,d.day);
var days = new Array
("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday")
return days[dt.getDay()]
}
After the open text question you can have an info node like this:

This will for example give this output if the answer on the date question was 2002-04-20:

Exercise 7: Course Registration


Let us say you want to build a questionnaire where people can register for weekly courses that are held on Mondays.
You want the respondents to provide the date they want to register for in an Open Text Question, but have to validate
the date format (which should be "MM/DD YYYY") and check that the date provided is a Monday and it is after the
current date.
Write a validation script for this question. Question ID is date4.
The answer is given in APPENDIX A Answers to Exercises.

Converting Data of Birth into Age (in number of years)

- 191 -
Forsta v2022 Scripting Manual Forsta Confidential

If you have an open text question dob where respondents insert their date of birth, you can calculate the respondent’s
age and set it in a hidden question age with the following script, which is placed in the validation code of the question:
var d = IsDateFmt(f("dob").get(),"YYYY-MM-DD");
if(!d)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Invalid date. Please use the format
YYYY-MM-DD");
}
else
{
var birthday = new Date();
birthday.setFullYear(d.year,d.month-1,d.day);
var today = new Date();
var years = today.getFullYear() - birthday.getFullYear();
birthday.setYear(today.getFullYear());
// If your birthday hasn't occurred yet this year, subtract 1.
if(today < birthday)
{
years-- ;
}
f("age").set(years);
}

14.1.3.3. The Date Question Type


A date question type is available that will give both a respondent interface for selecting a date and storing it in the
response database as a datetime variable,
The methods and properties available on the form object returned from f("q1") when q1 is a date question, are
described previously in chapters Conversion Methods in Forsta (see Conversion Methods in Forsta on page 24 for
more information), Methods of the Form Objects (see Methods of the Form Objects on page 42 for more information)
and The f Function (see The f Function on page 165 for more information). This section provides some examples of
using these methods.

Note: The Date question type is only available when using the Optimized Database format.

Set Current Date


If you would like to set current date in a hidden date question today, this can be done with the following script:
if(!f("today").toBoolean())
{
f("today").set(new Date());
}

Validating that Date answered is not after Current Date


In this example we have a date question date1. We want to validate that the date is not after the current date. This
can be done with the following script in the validation code field of the date question (date1).:
var dt = new Date(f("date1").year(),f("date1").month()-
1,f("date1").day());
var current = new Date();
if(dt.valueOf() > current.valueOf())
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please do not enter a date after the
current date.");
}
Here we declare two instances of the Date object, and set one of them (dt) to the date answered, and the other
(current) to the current date.

Converting Date of Birth into Age (in number of years)

- 192 -
Forsta Confidential Forsta v2022 Scripting Manual

If you have an date question dob where respondents insert their date of birth, you can calculate the respondent’s age
and set it in a hidden question age with the following script, which is placed in the validation code of the question:
var birthday = new Date(f("dob").year(),f("dob").month()-
1,f("dob").day());
var today = new Date();
var years = today.getFullYear() - birthday.getFullYear();
birthday.setYear(today.getFullYear());
// If your birthday hasn't occurred yet this year, subtract 1
if(today < birthday)
{
years-- ;
}
f("age").set(years);

14.2. The Math Object


The Math object provides a standard library of mathematical constants and functions. The Math object cannot be
created using the new operator, and gives an error if you attempt to do so. This is because it is a built-in object and
not an object type. Most of the properties and methods are different mathematical constants and functions that you
will seldom need to use in your questionnaires. The most important methods are the rounding methods (see Rounding
on page 194 for more information) and the random method (see Random on page 195 for more information).

14.2.1. Properties
The properties of the Math object are different mathematical constants.
Math.E
Euler's constant, the base of natural logarithms. The E property is approximately equal to 2.718.
Math.LN2
The natural logarithm of 2. The LN2 property is approximately equal to 0.693.
Math.LN10
The natural logarithm of 10. The LN10 property is approximately equal to 2.302.
Math.LOG2E
The base-2 logarithm of e, Euler's constant. The LOG2E property is approximately equal to 1.442.
Math.LOG10E
The base-10 logarithm of e, Euler's constant. The LOG10E property is approximately equal to 0.434.
Math.PI
, the ratio of the circumference of a circle to its diameter, approximately 3.141592653589793.
Math.SQRT1_2
The square root of ½, or one divided by the square root of 2. The SQRT1_2 property is approximately equal to 0.707.
Math.SQRT2
The square root of 2. The SQRT2 property is approximately equal to 1.414.

14.2.2. Math Object Methods


14.2.2.1. Trigonometric Functions
Math.cos(x)
returns the cosine of a numeric expression x.
Math.sin(x)
returns the sine of a numeric expression x.

- 193 -
Forsta v2022 Scripting Manual Forsta Confidential

Math.tan(x)
returns the tangent of a numeric expression x.
Math.acos(x)
returns the arc cosine of a numeric expression x.
Math.asin(x)
returns the arc sine of a numeric expression x.
Math.atan(x)
returns the arctangent of a numeric expression x.
Math.atan2(x,y)
Returns the angle of the polar coordinate corresponding to (x,y)

14.2.2.2. Rounding
Math.round(x)
returns a supplied numeric expression x rounded to the nearest integer. If the decimal portion of the number is 0.5 or
greater, the return value is equal to the smallest integer greater than the number. Otherwise, round returns the largest
integer less than or equal to the number. This is exactly as conventional rounding. For example, if we have a floating
point number between 0 and 2, values from 0 and up to but not including 0.5, will be rounded to 0. Values from and
including 0.5 and up to but not including 1.5 will be rounded to 1. Values from and including 1.5 up to and including 2,
will be rounded to 2.

Math.ceil(x)
returns the smallest integer greater than or equal to its numeric argument x, i.e. rounding up to the nearest integer.
For example, if we have a floating-point number between 0 and 2, the value 0 will be rounded to 0, and all values
greater than 0 and up to and including 1 will be rounded to 1. All values greater than 1 and up to and including 2 will
be rounded to 2.

Math.floor(x)
returns the greatest integer less than or equal to its numeric argument x, i.e. rounding down to the nearest integer.
For example, if we have a floating point number between 0 and 2, all values from 0 and up to, but not including 1, will
be rounded to 0. The value 1 and all values from 1 and up to but not including 2, will be rounded to 1, and the value 2
will be rounded to 2.

Rounding to a Number with Two Digits

- 194 -
Forsta Confidential Forsta v2022 Scripting Manual

If we ask people to provide their yearly salary and we want to compute the monthly salary, this can be done by
dividing the yearly salary by 12. However this might result in a number with many decimals. If for example we want the
result with an accuracy of two digits and need to round it, we can do that by multiplying the result by 100, then do the
rounding, and then divide the result with 100. Let us say the yearly salary is in the question yearly and the monthly
salary should be stored in the question monthly. Then we can use a script as below to set the monthly value:
var yearly : int = f("yearly").toNumber();
var monthly : float = yearly/12;
f("monthly").set(Math.round(monthly*100)/100);

14.2.2.3. Random
Math.random()
returns a random number between 0 and 1 (float), e.g. 0.523. The number generated is from 0 (inclusive) to 1
(exclusive), that is, the returned number can be zero, but it will always be less than one.
This is an extremely powerful feature to use in your surveys when you want to pick responses randomly, or send
random respondents to different parts of the questionnaire. Combined with conditions and arithmetic operations you
can program extremely powerful solutions for the selections (see SetRandomCategories on page 88 for more
information).

Picking n Random Items from the Answers to a Multi Question


If you have a multi question where the respondent picks some brands and want to proceed with more detailed
questions on some of the brands the respondent chooses, but not all, you can use a script to randomly pick some of
the brands the respondent selected. Let's say the multi question has question ID brands, and we have a hidden multi
question with the same answer list that has question ID random_brands.
var fromForm = f("brands");
var toForm = f("random_brands");
const numberOfItems : int = 3;

var available = new Set();


available = available.union(fromForm);
var selected = new Set();
if(available.size() <= numberOfItems)
{
selected = available;
}
else
{
while(selected.size() < numberOfItems)
{
var codes = available.members();
var randomNumber : float = Math.random()*codes.length;
var randomIndex : int = Math.floor(randomNumber);
var selectedCode = codes[randomIndex];
available.remove(selectedCode);
selected.add(selectedCode);
}
}

toForm.set(selected);
In this script we pick responses from a set of available responses (the answers to the multi question brands, stored in
the variable available) and add them to the set stored in the variable selected. At the end we set the selected
answers in the random_brands multi.
If there number of responses is less than or equal to numberOfItems (here: 3), we obviously include all those
responses. But if there are more than 3 responses, we have to pick random responses from the answers given.
The random picking is done in this while loop:

- 195 -
Forsta v2022 Scripting Manual Forsta Confidential

while(selected.size() < numberOfItems)


{
var codes = available.members();
var randomNumber : float = Math.random()*codes.length;
var randomIndex : int = Math.floor(randomNumber);
var selectedCode = codes[randomIndex];
available.remove(selectedCode);
selected.add(selectedCode);
}
We run through the loop until we have numberofItems responses (here 3) in the selected set. When a random
response is selected, we remove its code from the available set and insert it into the selected set. So
available will at any time hold the responses that have not been picked yet. At the start of each iteration inside the
loop we build an array codes with the available codes. The members method converts a set to an array.
Let us say we start with the codes "1","3","4" and "8". The array codes will consist of the following items in the first
iteration:
codes[0] = "1"
codes[1] = "3"
codes[2] = "4"
codes[3] = "8"
Math.random will give a number between 0 (inclusive) and 1 (exclusive). When this is multiplied with
codes.length (4 in our example), randomNumber will be set to a number between 0 (inclusive) and
codes.length (4) (exclusive):
0<=randomNumber<codes.length
i.e.
0<=randomNumber<4
in our example. Let us say that the number returned from Math.random is 0.6283. Then randomNumber will be
4*0.6283 = 2.5132.
This number is rounded down to the nearest integer by using the Math.floor method in the next step:
var randomIndex : int = Math.floor(randomNumber);
This means that randomIndex will be one of 0,1,2,...,codes.length-1, i.e. 0,1,2,3.

Important
Math.floor must be used, not Math.round or Math.ceil. Using Math.floor is the only way to ensure
that the probability of selecting the indexes is the same for all of them and that you get no errors.

Math.round would extend the set of possible picks with the index codes.length (i.e. the number 4 in our
example). This would cause problems because 4 is not an index in the array. If we used Math.ceil, we would round
up to the numbers 1,2,3 and 4, and could subtract 1 from these numbers to get the index. However, even though the
probability of this happening is extremely small, there is a small chance the number 0 would be returned from
Math.random(). And using Math.ceil on 0 would yield 0, and this would again cause problems.
In our example, where randomNumber was calculated to 2.5132, randomIndex will get the value 2.
codes[2] is "4", so the code 4 will be removed from the available set and added to the selected set.
The while loop will now continue to the next iteration with the remaining three codes, so in our example codes will be
have the following items in the next iteration:
codes[0] = "1"
codes[1] = "3"
codes[2] = "8"
Then the script will randomly pick one of these, and continue with this process until 3 items are selected.
Picking random items like this is best suited for surveys where the respondent is not allowed to modify previous
answers. If the respondent goes back to the brands question and then forwards again, the script is run again, possibly
resulting in a different set. So then the respondent will get questions for other brands. This may be confusing and
cause irritation for the respondent.

- 196 -
Forsta Confidential Forsta v2022 Scripting Manual

Randomly Assigning which Part of a Survey the Respondents Should Answer


To limit the number of questions each respondent has to answer in a long survey, you may want to split the survey
into different parts, and randomly pick which part a particular respondent should answer.
This can be done by randomly setting the response to a hidden single question, and then route the respondents to
their questions with conditions on this hidden question.
Let us say the hidden single question has question ID part. part can be set at the beginning of the survey with a script
like this:
var form = f("part");
if(!form.toBoolean())
{
var codes = form.domainValues();
var randomNumber : float = Math.random()*codes.length;
var randomIndex : int = Math.floor(randomNumber);
var code = codes[randomIndex];
form.set(code);
}
This is very similar to the previous example. Here we pick the code from an array of all codes from the answer list of
the hidden single question part (using domainValues).
The condition with toBoolean is used so that the single question is set only the first time the script is run. So this
solution will work even when the respondent is allowed to modify previous answers.
See also the built-in function SetRandomCategories (see SetRandomCategories on page 88 for more information).

14.2.2.4. Maximum and Minimum


Math.max({number1{, number2{...{, numberN}}}})
Math.min({number1{, number2{...{, numberN}}}})
max returns the greater of zero or more supplied numeric expressions. min returns the lesser of zero or more supplied
numeric expressions. The curly brackets are used to indicate that the numerical expressions number1,...,numberN
are optional.
If no arguments are provided, the return value is equal to negative infinity for max and positive infinity for min. If any
argument is NaN, the return value is also NaN (Not a Number).
However, we would recommend using the Forsta functions Max and Min(see Max and Min on page 77 for more
information) when working on questions, since these functions automatically converts the answers to numbers.

14.2.2.5. Absolute value


Math.abs(number)
abs returns the absolute value of a numeric expression number.
abs can for example be used when you want the difference between two numbers as a positive number, no matter
which of them is the highest number.
Math.abs(x-y)
If x is 10 and y is 4, x-y will return 6. If x is 4 and y is 10, x-y will return –6. The absolute value will be 6 for both.

14.2.2.6. Exponents, Logarithms and Square Root


Math.exp(number)
exp returns e (the base of natural logarithms) raised to a power, e number.
e is Euler's constant, approximately equal to 2.178.
Math.log(number)
log returns the natural logarithm of a number. The base is e, Euler's constant, approximately equal to 2.178.
Math.pow(base, exponent)

- 197 -
Forsta v2022 Scripting Manual Forsta Confidential

pow returns the value of a base expression taken to a specified power, baseexponent.
Math.sqrt(number)
Returns the square root of a numeric expression number. If number is negative, the return value is zero.

14.3. The String Object


The String object type allows strings to be accessed as objects. It allows manipulation and formatting of text strings
and determination and location of sub-strings within strings.

14.3.1. Constructors
An instance of the String object can be created like this:
newString = new String({"stringLiteral"});
The curly brackets are used to indicate that the string literal is optional.
String objects can also be created implicitly using string literals.
newString = "{stringLiteral}";
or
newString : String = "{stringLiteral}";

14.3.2. Properties
strVariable.length
"String Literal".length
length returns the length of a String object, an integer with the number of characters in the String object.

14.3.3. Index
Many of the methods of the String object refer to index on a string. The index is used to refer to a characters
position within a string. If you have the string
0 1 2 3 4 5 6 7 8 9101112131415
"This is a string"
the character a has index 8, because the index starts at 0 for first character. The index of the last character will always
be 1 less than the string's length. This is similar to indexing in arrays.

14.3.4. Converting to String from Other Types


Often you want to convert variables of different types to string to use some of the string methods to manipulate on the
content. The easiest way of converting a variable to a string, is to concatenate it with an empty string using the +
operator:
variable+""
Since string has higher order of precedence than other types, this will convert the variable to type string. You can also
use the .toString() method.

14.3.5. Methods for String Objects


Some methods for the string objects that use Regular Expressions are described elsewhere in the manual (see String
Object Methods that Use Regular Expression Objects on page 213 for more information). The remainder are
described below.

14.3.5.1. Methods Returning a Character or a Character Code at a Specific Index


strObj.charAt(index)
charAt returns the character at the specified index. Valid values for index are between 0 and the length of the
string minus 1. charAt with an index out of valid range returns an empty string.

- 198 -
Forsta Confidential Forsta v2022 Scripting Manual

strObj.charCodeAt(index)
charCodeAt returns an integer representing the Unicode encoding of the character at the specified index. index is
a number between 0 and the length of the string minus 1. If there is no character at the specified index, NaN is
returned.

14.3.5.2. Building a String from a Number of Unicode Characters


String.fromCharCode({code1{, code2{, ...{, codeN}}}})
fromCharCode returns a string from a number of Unicode character values. If no arguments are supplied, the result
is the empty string.
A String object need not be created before calling fromCharCode. The method can be applied directly on the object
type.
In the following example, txt is set to the string "Confirmit":
var txt = String.fromCharCode(67,111,110,102,105,114,109,105,116);
This is a way to be able to set Unicode text in scripts.

14.3.5.3. Changing Case


strObj.toLowerCase()
toLowerCase returns a string where all alphabetic characters have been converted to lowercase.
strObj.toUpperCase()
toUpperCase returns a string where all alphabetic characters have been converted to uppercase.
Both of these methods have no effect on non-alphabetic characters.

Checking a User Name and Password where Username is Case Insensitive


You can password-protect an open survey with a password and user name combination that is the same for all
respondents. This can be used when you do not upload any respondent list before starting the survey, but still want to
limit the access to the survey. You should be aware that this would not stop the respondents from accessing the
survey more than once (see Validation Code on page 8 for more information).
The user name and password can be given in two open text questions, username and password, the latter with the
password property. If you want the password to be case sensitive, but not the username you can use a validation
code like this:
if(f("username").get().toUpperCase() != "USERNAME" || f("password").get()
!= "Password")
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Wrong username or password. Please
try again.");
}

14.3.5.4. Searching for a Substring within a String


strObj.indexOf(subString{, startIndex})
indexOf returns the character position of the first occurrence of a string subString within a String
object. startIndex is optional, and is an integer value specifying the index to begin the search. If omitted,
searching starts at the beginning of the string. If the subString is not found, -1 is returned.
If startIndex is negative, startIndex is treated as zero. If it is larger than the greatest character position index, it
is treated as the largest possible index.
Searching is performed from left to right.
strObj.lastIndexOf(substring{, startindex})

- 199 -
Forsta v2022 Scripting Manual Forsta Confidential

returns the character position of the last occurrence of a subString within a String object. startIndex is
optional, and is an integer value specifying the index to begin searching within the String object. If omitted,
searching begins at the end of the string. If the subString is not found, a-1 is returned.
If startIndex is negative, startIndex is treated as zero. If it is larger than the greatest character position index, it
is treated as the largest possible index.
Searching is performed right to left.

On the Fly Recoding


You may use the indexOf method to search for strings within a text. This can be done to simplify the coding. For
example if you have an open text question about car brands you can search for strings like VOLVO or FORD as
below:
if(f("openbrands").get().toUpperCase().indexOf("FORD") != -1)
{
f("brands")["1"].set("1");
}
if(f("openbrands").get().toUpperCase().indexOf("MERCEDES") != -1)
{
f("brands")["2"].set("1");
}
if(f("openbrands").get().toUpperCase().indexOf("VOLVO") != -1)
{
f("brands")["3"].set("1");
}
and so on. (openbrands is here the open text question, and brands is a hidden multi question used e.g. for reporting).
Here we use toUpperCase to convert case to make the search case insensitive, so that the strings "Volvo",
"volvo" and "VOLVO" all will be recognized.
If indexOf returns anything different from –1, it means that the string has been found in the openbrands question.
The problem with this solution is respondents who spell brand names wrongly. You can of course check for different
common misspellings ("VOVLO" etc.) but usually you will need some form of manual coding as well.

14.3.5.5. Retrieving a Section of a String (Substring)


stringObj.slice(start, {end})
returns a section of a string. start is required and is the index of the first character in the section of stringObj.
end is optional and is the index after the last character in the section of stringObj. The slice method copies up to,
but not including, the element indicated by end.
In this example:
var txt = "The methods of the String Object can be used for text
manipulation.";
var section = txt.slice(19,32);
section will be set to the substring
"String Object"
If start is negative, it is treated as length+start where length is the length of the string. If end is negative, it is
treated as length+end where length is the length of the string. If end is omitted, extraction continues to the end of
stringObj. If end occurs before start, no characters are copied to the new string.
stringObj.substr(start {, length })
returns a substring beginning at a specified location start and having a specified length.
start is required, and is the starting position (index) of the desired substring. length is optional and is the number
of characters to include in the returned substring.
If length is zero or negative, an empty string is returned. If not specified, the substring continues to the end of the
string.

- 200 -
Forsta Confidential Forsta v2022 Scripting Manual

stingObj.substring(start, end)
returns the substring at the specified location within a String object.
start is the index indicating the beginning of the substring and end is the index indicating the end of the substring.
The substring method returns a string containing the substring from start up to, but not including, end.
The substring method uses the lower value of start and end as the beginning point of the substring. For
example, stringObj.substring(0,3) and stringObj.substring(3,0) return the same substring.
If either startor end is NaN or negative, it is replaced with zero.
The length of the substring is equal to the absolute value of the difference between start and end. For example,
the length of the substring returned in stringObj.substring(0,3) and strObj.substring(3,0) is three.

Replacing Last Comma with "and" in a Listing of Answers


If you refer to a multi question, e.g. brands, in response piping with ^'s in a question text, then the last two items in the
listing are separated with "and" in English.
^f("brands")^
If the brands "Ford","Mercedes","Volvo" are answers to the brands question, the string returned will be "Ford,
Mercedes and Volvo".
However, when you refer to
f("brands").categoryLabels()
in a script node, e.g. to include the answers in an email text, the result will be an array with the elements. When this is
converted to a string (for example by adding it to a string expression), you get a string that lists the elements
separated with commas, but not with "and" between the last two elements: "Ford,Mercedes,Volvo".
The following script will replace the last comma with " and ". (Observe the spaces in front of and after and).
var body : String = "";
body += "Here are the answers on the brands question:\n\n"

var form = f("brands");


body += form.categoryLabels();

if(form.size() > 1)
{
body = body.substring(0,body.lastIndexOf(",")) + " and " +
body.substring(body.lastIndexOf(",")+1,body.length);
}
SendMail("[email protected]",f("email"),"Answers",body);
If there are two answers or more, the answers string will be set to the substring from the beginning of the answers
string to (but excluding) the last comma, the string " and " and the substring from the character after the last
comma to the end of the answers string.

14.3.5.6. Splitting and Joining Strings


stringObj.split({separator{, limit})
split returns the array of strings that results when a string is separated into substrings. separator is a string or an
instance of a Regular Expression object (see The Regular Expression Object on page 212 for more information)
identifying one or more characters to use in separating the string. If omitted, a single-element array containing the
entire string is returned. limit is a value used to limit the number of elements returned in the array. The result of the
split method is an array of strings split at each point where separator occurs in stringObj. stringObj itself is
not modified. The separator is not returned as part of any array element.
string1.concat({string2{, string3{, . . . {, stringN}}}})
concat returns a string value containing the concatenation of two or more supplied strings. The result of the concat
method is equivalent to:
string1 + string2 + string3 + ... + stringN.

- 201 -
Forsta v2022 Scripting Manual Forsta Confidential

Generating an Array from a String with Values


Let us say you send in information of what products the respondent uses with the url to an open survey, for example
like this:
http://survey.confirmit.com/wix/pXXXXXXXX.aspx?products=1x15x17x19
http://survey.confirmit.com/wix/pXXXXXXXX.aspx?products=6x11x20
1, 6, 11, 15, 17, 19 and 20 are different product codes, and the respondent can have any number of these. Sending
them in like this gives more condensed urls than sending in one value (yes/no) for each product. It could possibly be a
very long list of products.
In the Forsta survey we capture the products list with Request(see Request on page 228 for more information), and
want to set a hidden multi question products with the values sent in with the url. The products multi question uses
codes that are equal to the product codes that are sent in with the url.
To be able to set the products question, we have to split the string returned from Request("products") with "x" as
delimiter to get an array with the product codes sent in:
var txt : String = Request("products")+"";

var productArray = txt.split("x");


f("products").set(productArray);

14.3.5.7. Retrieving the String Value


strObj.toString()
strObj.valueOf()
Both toString and valueOf returns the string value of the String object.

14.3.5.8. Methods that Add HTML Tags to a String


There are a number of methods available that adds HTML code to your strings. They are listed in the table below.
They may for example be used in your error messages, or in expressions that will be displayed in info or question
titles, texts or answers (with response piping).

Method Equivalent to

strVariable.anchor(anchorString) strVariable = '<A NAME="'+ anchorString + '">' + strVariable +


'</A>'

strVariable.big() strVariable = '<BIG>' + strVariable + '</BIG>'

strVariable.blink() strVariable = '<BLINK>' + strVariable + ' </BLINK>'

strVariable.bold() strVariable = '<B>' + strVariable + '</B>'

strVariable.fixed() strVariable = '<TT>' + strVariable + '</TT>'

strVariable.fontcolor(colorVal) strVariable = '<FONT COLOR="' + colorVal + '">' + strVariable +


'</FONT>'

strVariable.fontsize(intSize) strVariable = '<FONT SIZE="' + intSize + '">' + strVariable +


'</FONT>'

strVariable.italics() strVariable = '<I>' + strVariable + '</I>'

strVariable.link(linkstring) strVariable = '<A HREF="' + linkstring + '">' + strVariable + '</A>'

- 202 -
Forsta Confidential Forsta v2022 Scripting Manual

strVariable.small() strVariable = '<SMALL>' + strVariable + '</SMALL>'

strVariable.strike() strVariable = '<STRIKE>' + strVariable + '</STRIKE>'

strVariable.sub() strVariable = '<SUB>' + strVariable + '</SUB>'

strVariable.sup() strVariable = '<SUP>' + strVariable + '</SUP>'

14.3.5.9. Removing Leading/Trailing White Space Characters


strObj.Trim()
This method returns a string with all leading/trailing white-space characters removed from the String object. Note that
it returns a new string object rather than modifying the existing object. For example in order to remove the
leading/trailing spaces from a respondent’s Open Text answer the following can be used:
f(qid).set(f(qid).get().Trim())

14.4. Regular Expressions


Regular Expressions are character-matching patterns that are used to find and/or replace character patterns in
strings.
With Regular Expressions, you can:

• Test for a pattern within a string. For example, you can test an input string to see if a telephone number
pattern or a credit card number pattern occurs within the string.
• Replace text. You can use a Regular Expression to identify specific text in a string and either remove it
completely or replace it with other text.
• Extract a substring from a string based upon a pattern match.
The syntax of Regular Expressions is not easy to understand. If you have problems understanding it, you are advised
to check the examples, try to modify them and test what the differences are. The Perl scripting language popularized
Regular Expressions, and JScript 's support of Regular Expressions is based on that of Perl. So for further reading
about Regular Expressions, you may search for Perl documentation in addition to JScript . NET documentation.
Regular Expressions are implemented as Regular Expression objects, and are created as follows:
var re = /pattern/{flags};
(similar to Regular Expressions in Perl) or
var re = new RegExp("pattern",{"flags"});
(similar to normal syntax for instantiating an object in JScript .NET)
pattern is the pattern to be matched and the optional flags is a string containing i, and/or m. The i stands for
ignore case and the m for multi-line search.

Important
When defining a Regular Expression with the syntax /pattern/flags, do not use quotation marks around
the strings. However when using the other notation you must use them.

var re = new RegExp("Forsta","i");


is the same as
var re = /Forsta/i;
This matches all occurrences of "Forsta".

- 203 -
Forsta v2022 Scripting Manual Forsta Confidential

14.4.1. Regular Expression Syntax


A Regular Expression is a pattern of text that consists of ordinary characters (for example, letters a through z) and
special characters, known as meta characters. The pattern describes one or more strings to match when searching a
body of text. The Regular Expression serves as a template for matching a character pattern to the string being
searched. This is similar to the expressions used for example when searching in the project list in Forsta. However,
Regular Expressions are far more flexible and complex than that.

14.4.1.1. Ordinary Characters


Ordinary characters consist of all characters that are not explicitly designated as meta characters. This includes:

• all upper- and lowercase alphabetic characters,


• all digits,
• all punctuation marks,
• some symbols.
The simplest form of a Regular Expression is a single, ordinary character that matches itself in a searched string. For
example, the single-character pattern
/a/
matches the letter a wherever it appears in the searched string.
You can combine a number of single characters together to form a larger expression.
/arm/
This expression describes a pattern with these three characters joined together. Note that there is no concatenation
operator. All that is required is that you put one character after another.
The match will be found in the string
"Those people are harmless."
but not in the string
"Those people are my family."
Even though the second string has the characters a, r and m, they are not joined together, so no match is found.

14.4.1.2. Special Characters


There are a number of meta characters that require special treatment when trying to match them. To match these
special characters, you must first escape them, that is, precede them with a backslash character (\).
The table below shows those special characters and their meanings. More detailed explanations are given in the
following sections.

Special Comment
Character

$ Matches the position at the end of an input string. If the multi-line (m) property is set, $ also matches
the position preceding \n or \r. (newline or carriage return).

() Marks the beginning and end of a sub expression. Sub expressions can be captured for later use.

* Matches the preceding sub expression zero or more times.

+ Matches the preceding sub expression one or more times.

- 204 -
Forsta Confidential Forsta v2022 Scripting Manual

. Matches any single character except the newline character \n.

[ Marks the beginning of a bracket expression.

? Matches the preceding sub expression zero or one time, or indicates a "non-greedy" quantifier.

\ Marks the next character as a special character, a literal, a back-reference, or an octal escape.

^ Matches the position at the beginning of an input string except when used in a bracket expression
where it negates the character set. If the multi-line property is set, ^ also matches the position
following \n or \r (newline or carriage return).

{ Marks the beginning of a quantifier expression.

| Indicates a choice between two items (or).

To match any of these characters themselves, they must be preceded with \:

Expression Matches

\$ $

\( (

\) )

\* *

\+ +

\. .

\[ [

\? ?

\\ \

\^ ^

\{ {

\| |

/Forsta\?/
matches the string "Forsta?"

- 205 -
Forsta v2022 Scripting Manual Forsta Confidential

14.4.1.3. Non-Printable Characters


A number of useful non-printing characters are occasionally used. The table below shows the escape sequences used
to represent those non-printing characters:

Character Meaning

\cx Matches the control character indicated by x. For example,


\cM
matches a Control-M or a carriage return character. The value of x must be in the range of A-Z or a-
z. If not, c is assumed to be a literal 'c' character.

\f Matches a form-feed character.

\n Matches a newline character.

\r Matches a carriage return character.

\s Matches any white space character including space, tab, form-feed, etc.

\S Matches any non-white space character.

\t Matches a tab character.

\v Matches a vertical tab character.

x represents a character in the range A-Z or a-z.

14.4.1.4. Bracket Expressions


Many times, it's useful to match specified characters from a list. For example, you may want to search a string for
chapter headings that are expressed as Chapter 1, Chapter 2, etc.
You can create a list of matching characters by placing one or more individual characters within square brackets ([
and ]). When characters are enclosed in brackets, the list is called a bracket expression.
Within brackets, as anywhere else, ordinary characters represent themselves, that is, they match an occurrence of
themselves in the input text. Most special characters lose their meaning when they occur inside a bracket expression.
There are some exceptions:
The ] character ends a list if it is not the first item. To match the ] character in a list, place it first, immediately following
the opening [.
The \ character continues to be the escape character. To match the \ character itself, use \\.
Characters enclosed in a bracket expression match only a single character for the position in the Regular Expression
where the bracket expression appears. The following Regular Expression matches 'Chapter 1', 'Chapter 2', 'Chapter
3', 'Chapter 4', and 'Chapter 5':
/Chapter [12345]/
If you want to express the matching characters using a range instead of the characters themselves, you can separate
the beginning and ending characters in the range using the hyphen (-) character. The Unicode character value of the
individual characters determines their relative order within a range. The following Regular Expression is equivalent to
the bracketed list shown above.
/Chapter [1-5]/

- 206 -
Forsta Confidential Forsta v2022 Scripting Manual

When a range is specified in this manner, both the starting and ending values are included in the range. It is important
to note that the starting value must precede the ending value in Unicode sort order.
If you want to include the hyphen character (-) in your bracket expression, you must do one of the following:
Escape it with a backslash:
[\-]
Put the hyphen character at the beginning or the end of the bracketed list. The following expressions match all
lowercase letters and the hyphen:
[-a-z][a-z-]
Create a range where the beginning character value is lower than the hyphen character and the ending character
value is equal to or greater than the hyphen. Both of the following Regular Expressions satisfy this requirement:
[!--][!-~]
i.e. characters from ! to – or from ! to ~.
If you want to find all the characters not in the list or range, you can place the caret (^) character at the beginning of
the list. If the caret character appears in any other position within the list, it matches itself, that is, it has no special
meaning. The following Regular Expression matches chapter headings with numbers different from 1,2,3,4 and 5 (and
any other characters different from 1,2,3,4 and 5):
/Chapter [^12345]/
The same expressions above can be represented using the hyphen character (-).
/Chapter [^1-5]/
A typical use of a bracket expression is to specify matches of any upper- or lowercase alphabetic characters or any
digits. The following JScript .NET expression specifies such a match:
/[A-Za-z0-9]/

Character Description

[xyz] A character set. Matches any one of the enclosed characters.

[^xyz] A negative character set. Matches any character not enclosed.

[a-z] A range of characters. Matches any character in the specified range.

[^a-z] A negative range characters. Matches any character not in the specified
range.

a, x, y and z represent characters.

14.4.1.5. Quantifiers
Sometimes, you don't know how many characters there are to match. In order to accommodate that kind of
uncertainty, Regular Expressions support the concept of quantifiers. These quantifiers let you specify how many
times a given component of your Regular Expression must occur for your match to be true.
The following table illustrates the various quantifiers and their meanings:

Character Description

- 207 -
Forsta v2022 Scripting Manual Forsta Confidential

* Matches the preceding sub-expression zero or more times.

+ Matches the preceding sub-expression one or more times.

? Matches the preceding sub-expression zero or one time.

{n} Matches exactly n times, where n is a non-negative integer..

{n,} Matches at least n times, where n is a non-negative integer

{n,m} Matches at least n and at most m times. m and n are non-negative integers, where n <= m.

n and m are integers.


With a large input document, chapter numbers could easily exceed nine, so you need a way to handle chapter
numbers with more than one digit. Quantifiers give you that capability. The following JScript .NET Regular Expression
matches chapter headings with any number of digits:
/Chapter [1-9][0-9]*/
The first bracket expression [1-9] makes sure that the first digit is in the range 1-9. The second bracket expression
with quantifier [0-9]* searches for 0 or more digits in the range 0-9. The quantifier (*) appears after the range
expression.

14.4.1.6. Anchors
All the examples so far have recognized patterns anywhere in a string. But you may want the patterns to match only if
they e.g. appear at the beginning of the string. Anchors provide that capability.
Anchors allow you to fix a Regular Expression to either the beginning or end of a string. They also allow you to create
Regular Expressions that occur either within a word or at the beginning or end of a word. The following table contains
the list of Regular Expression anchors and their meanings:

Character Description

^ Matches the position at the beginning of the input string. If the multi-line property is set, ^ also
matches the position following \n or \r (newline or carriage return).

$ Matches the position at the end of the input string. If the multi-line property is set, $ also
matches the position preceding \n or \r (newline or carriage return).

\b Matches a word boundary, that is, the position between a word and a space.

\B Matches a non-word boundary.

You cannot use a quantifier with an anchor. Since you cannot have more than one position immediately before or after
a newline or word boundary, expressions such as ^* are not permitted.
To match text at the beginning of a line of text, use the ^ character at the beginning of the Regular Expression. This is
different from using the ^ within a bracket expression.
To match text at the end of a line of text, use the $ character at the end of the Regular Expression.

- 208 -
Forsta Confidential Forsta v2022 Scripting Manual

To use anchors when searching for chapter headings, the following JScript .NET Regular Expression matches a
chapter heading with up to two following digits that occur at the beginning of a line and where there is no text after the
heading:
/^Chapter [1-9][0-9]?$/
Matching word boundaries is a little different but adds a very important capability to Regular Expressions. A word
boundary is the position between a word and a space. A non-word boundary is any other position. The following
JScript .NET expression matches the first three characters of the word 'Chapter' because they appear following a
word boundary:
/\bCha/
The position of the '\b' operator is critical here. If it's positioned at the beginning of a string to be matched, it looks for
the match at the beginning of the word; if it's positioned at the end of the string, it looks for the match at the end of the
word. For example, the following expressions match 'ter' in the word 'Chapter' because it appears before a word
boundary:
/ter\b/

14.4.1.7. Alternation and Grouping


Alternation allows use of the | (pipe) character to allow a choice between two or more alternatives, a bit similar to or
in Boolean expressions. Expanding the chapter heading Regular Expression, you can expand it to cover more than
just chapter headings – for example sections as well. However, it's not as straightforward as you might think. You
might think that the following expressions match one or two digits after either 'Chapter' or 'Section' , between the
beginning and ending of a line:
/^Chapter|Section [1-9][0-9]?$/
Unfortunately, what happens is that the Regular Expressions shown above will have two different parts, so this will be
equal to getting a match on either of these two expressions:
/^Chapter/
or
/Section [1-9][0-9]?$/
So it will match either the word 'Chapter' at the beginning of a line, or 'Section' and 1-2 numbers at the end of the line.
You can use parentheses to limit the scope of the alternation, that is, make sure that the alternation applies only to the
two words, 'Chapter' and 'Section'. However, parentheses are tricky as well, because they are also used to create sub
expressions. By taking the Regular Expressions shown above and adding parentheses in the appropriate places, you
can make the Regular Expression match either 'Chapter 1' or 'Section 3'.
/^(Chapter|Section) [1-9][0-9]?$/
These expressions work properly except that a by-product occurs. Placing parentheses around 'Chapter|Section'
establishes the proper grouping, but it also causes either of the two matching words to be captured for future use. So
a sub match is captured. In this example we really do not need that sub match.
In the examples shown above, all you really want to do is use the parentheses for grouping a choice between the
words 'Chapter' or 'Section'. You do not necessarily want to refer to that match later. We recommend that unless you
really need to capture sub matches, do not use them. Your Regular Expressions will be more efficient since they will
not have to take the time and memory to store those sub matches.
You can use ?: before the Regular Expression pattern inside the parentheses to prevent the match from being saved
for possible later use. The following modification of the Regular Expressions shown above provides the same
capability without saving the sub match.
/^(?:Chapter|Section) [1-9][0-9]?$/
There are times you'd like to be able to test for a pattern without including that text in the match. For instance, you
might want to match the protocol in a URL (like http or ftp), but only if that URL ends with .com. Or maybe you want to
match the protocol only if the URL does not end with .edu. In cases like those, you'd like to "look ahead" and see how
the URL ends. A lookahead assertion is handy here.
There are two non-capturing meta characters used for lookahead matches:

- 209 -
Forsta v2022 Scripting Manual Forsta Confidential

A positive lookahead, specified using ?=, matches the search string at any point where a matching Regular
Expression pattern in parentheses begins.
A negative lookahead, specified using ?!, matches the search string at any point where a string not matching the
Regular Expression pattern begins.
If you want to search for the protocol in a url like "http://www.confirmit.com", but only if it ends with .com:
/^[^:]+(?=.*\.com$)/
Because of the anchor ^, the match is found at the beginning of the string. Then the first part
[^:] +
searches for one or more characters different from :. One or more because of the quantifier +, different from : because
of the bracket expression [^:]
Then there is a positive lookahead:
(?=.*\.com$)
which searches through the string to find a match for
.* \.com$
Because of the anchor $ this has to be at the end of the string. . matches any character except the newline character,
and because of the quantifier * we can have 0 or more of these characters before the last part, which is the character .
(which has to be escaped with backslash \) followed by com – i.e. ".com".
But the match will be for the first part of the string, i.e. "http" in "http://www.confirmit.com".
Similarly, the expression
/^[^:]*(?!.*\.edu$)/
will search for the first characters until : is reached in a string not ending with ".edu".

Character Description

Matches pattern and captures the match. The captured match can be retrieved from the
(pattern)
resulting Matches collection, using the $0...$9 properties in JScript .NET.

(?:pattern) Matches pattern but does not capture the match (it is not stored for possible later use).

Positive look-ahead matches the search string at any point where a string-matching pattern
begins. The match is not captured for possible later use. After a match occurs, the search for
(?=pattern)
the next match begins immediately following the last match, not after the characters that
comprised the look-ahead.

Negative look-ahead matches the search string at any point where a string not matching
pattern begins. The match is not captured for possible later use. After a match occurs, the
(?!pattern)
search for the next match begins immediately following the last match, not after the characters
that comprised the look-ahead.

14.4.1.8. Back-References
You can store a part of a matched pattern for later reuse. Placing parentheses around a Regular Expression pattern
or part of a pattern causes that part of the expression to be stored into a temporary buffer.
Each captured sub-match is stored as it is encountered from left to right in a Regular Expressions pattern. The sub-
matches are numbered beginning at 1 and continuing up to a maximum of 99 sub-matches. Each different buffer can
be accessed using

- 210 -
Forsta Confidential Forsta v2022 Scripting Manual

\n
where n is one or two decimal digits identifying a specific buffer, e.g. \1.
For example, back-references can be used to check for double occurrences of the same words, e.g. in a string such
as:
Scripting is is fun!
The following JScript .NET Regular Expression uses a single sub-expression to check for duplicates:
/\b([a-z]+) \1\b/gim
The sub-expression is everything between parentheses. That captured expression includes one or more alphabetic
characters, as specified by [a-z]+. The second part of the Regular Expression (\1) is the reference to the previously
captured sub-match, that is, the second occurrence of the word. \b is used for word boundary, so that the check is
done on complete words.

14.4.1.9. Digits and Word Characters

Character Description

\d Matches a digit character. Equivalent to [0-9].

\D Matches a non-digit character. Equivalent to [^0-9].

\w Matches any word character including underscore. Equivalent to A-Za-z0-9_].

\W Matches any non-word character. Equivalent to [^A-Za-z0-9_].

14.4.1.10. Hexadecimal and Octal Escape Values and Unicode Characters

Character Description

Matches n, where n is a hexadecimal escape value. Hexadecimal escape values must be


\xn exactly two digits long. For example, '\x41' matches "A". '\x041' is equivalent to '\x04' & "1".
Allows ASCII codes to be used in Regular Expressions.

Identifies either an octal escape value or a back-reference (see Back-References on page 210
\num
for more information).

Matches n, where n is a Unicode character expressed as four hexadecimal digits. For


\un
example, \u00A9 matches the copyright symbol (©).

Since \ followed by a number num can represent both octal escape values and back-references, the following rules
apply:
If num has one digit and \num is preceded by at least num captured sub expressions, num is a back-reference.
Otherwise, num is an octal escape value if num is an octal digit (0-7).

- 211 -
Forsta v2022 Scripting Manual Forsta Confidential

If num has two digits and \num is preceded by at least num captured sub expressions, num is a back-reference. If the
first digit is n, and \num is preceded by at least n captures, n is a back-reference followed by a literal, the second
digit. If neither of these applies, \num matches an octal escape value when the number is an octal (both digits in the
range 0-7).
If num has three digits, it matches an octal escape value when the first digit is 0-3 and the two last digits are octal
digits (0-7).

14.4.2. Order of Precedence


Once you have constructed a Regular Expression, it is evaluated much like an arithmetic expression, that is, it is
evaluated from left to right and follows an order of precedence. The following table illustrates, from highest to lowest,
the order of precedence of the various Regular Expression operators:

Operator(s) Description

\ Escape

(), (?:), (?=), [] Parentheses and Brackets

*, +, ?, {n}, {n,}, {n,m} Quantifiers

^, $, \anymetacharacter Anchors and Sequences

| Alternation

14.4.3. The Regular Expression Object


We have already seen the two ways of instantiating a Regular Expression object:
var re = /pattern/{flags}
and
var re = new RegExp("pattern",{"flags"})
Regular Expression objects store patterns used when searching strings for character combinations. After the Regular
Expression object is created, it is either passed to a String method, or a string is passed to one of the Regular
Expression methods.

14.4.3.1. Regular Expression Methods


rgExp.exec(str)
exec executes a search on a string str using a Regular Expression pattern defined in an instance of a Regular
Expression object rgExp, and returns an array containing the results of that search.
If the exec method does not find a match, it returns null. If it finds a match, exec returns an array. Element zero of
the array contains the entire match, while elements 1 – n contain any sub matches that have occurred within the
match.
rgExp.test(str)
test returns a Boolean value (true or false) that indicates whether or not a pattern defined in the Regular
Expression rgExp exists in a searched string str.
The test method returns true if the pattern exists in the string, and false otherwise.

Validation of the Format of a Phone Number

- 212 -
Forsta Confidential Forsta v2022 Scripting Manual

Let us say you want the respondent to specify his phone number in a particular format, allowing a digit or + as the first
character and spaces between number sets, but no other characters. The following validation code uses a Regular
Expression to check the formatting of the phone number, provided that the phone number is applied in an open text
question with question ID phone:
var num : String = f("phone").get();
var re = /^(?:\d|\+)(?:\d| )+$/;
if(!re.test(num))
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please provide your phone number,
only using digits and space, and with + before your country code if it is
a foreign number.");
}
The Regular Expression starts the search at the beginning of the string (^). Then the first character should be either a
digit or + (?:\d|\+). Because of ?: this sub expression is not stored. Then the rest of the string consists of one or more
digits or spaces (?:\d| ) until the end of the string is reached ($).
In this script there are no restrictions on number of spaces or digits.
Exercise 8: Restricting the Number of Digits in a Phone Number
Based on the previous example, please modify the Regular Expression so that it checks that the phone number is on
the format xxx xxx xxxx – i.e. 3 groups of 3+3+4 digits separated with space. (This time with no + for country code).
The answer is given in APPENDIX A Answers to Exercises.

14.4.4. String Object Methods that Use Regular Expression Objects


There are three methods of the String Object that uses Regular Expressions as input.
stringObj.match(rgExp)
match executes a search on a string using a Regular Expression pattern, and returns an array containing the results
of that search.
If the match method does not find a match, it returns null.
If it finds a match, match returns an array. If the global flag (g) is not set, element zero of the array contains the entire
match, while elements 1 – n contain any sub matches that have occurred within the match. If the global flag is set,
elements 0 - n contain all matches that occurred.
stringObj.replace(rgExp, replaceText)
replace returns a copy of a string with rgExp replaced with replaceText. The string stringObj is not modified
by the replace method.
rgExp can be an instance of a Regular Expression object or a String object or literal. If rgExp is not an instance of a
Regular Expression object, it is converted to a string, and an exact search is made for the results; no attempt is made
to convert the string into a Regular Expression.
replaceText is a String object or string literal containing the text to replace for every successful match of rgExp in
stringObj. It can also be a function that returns the replacement text.
Returned from the replace method is a copy of stringObj after the specified replacements have been made.
stringObj.search(rgExp)
search returns the position of the first substring match in a Regular Expression search using the Regular Expression
object rgExp.
The search method indicates if a match is present or not. If a match is found, search returns an integer value that
indicates the index from where the match occurred. If no match is found, it returns -1.

Using Regular Expression to Replace Commas With Line Breaks

- 213 -
Forsta v2022 Scripting Manual Forsta Confidential

If you want to send an email and in the email text list the answers to a multi question from the survey, you can use
categoryLabels. Converted into a string this will give the items separated by commas. If you want to have the
answers on one line each instead of separated by commas you have to replace the commas with line breaks. If the
email is sent as plain text, you then have to replace the commas with the special character \n.
This script will replace the commas in a listing of the answers given on a multi question brands:
var body : String = "";
body += "Here are the answers on the brands question:\r\n\r\n"

var brandsAnswers = f("brands").categoryLabels();


brandsAnswers = brandsAnswers.toString();
brandsAnswers = brandsAnswers.replace(/,/g,"\r\n");

body += brandsAnswers

SendMail("[email protected]",f("email"),"Answers",body);
If the mail is sent as HTML, you have to replace the commas with the HTML <br> tag instead:
var body : String = "";
body += "Here are the answers on the brands question:<br><br>"

var brandsAnswers = f("brands").categoryLabels();


brandsAnswers = brandsAnswers.toString();
brandsAnswers = brandsAnswers.replace(/,/g,"<br>");

body += brandsAnswers

SendMail("[email protected]",f("email"),"Answers",body,"","",0,0)
;

Post Codes in the United Kingdom


Post codes in the UK can be in the following formats:
LN NLL
LLN NLL
LNN NLL
LLNN NLL
LLNL NLL
LNL NLL
where L is a letter and N is a number. A post code is one or two letters, followed by either one number and an optional
letter or by two numbers,AND then a space and a number and two letters.
A validation script for post codes for the UK could be as shown below, with the open text question postalcode:
var pcode : String = f("postalcode").get();
var re = /^((?:(?:[a-z]{1,2}\d{1,2}|[a-z]{2}\d[a-z]|[a-z]\d[a-z]) \d[a-
z]{2}))$/i;
if(pcode.search(re) == -1)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please provide a post code using a
valid format.");
}
We allow both upper and lower case letters (i). The first half of the valid formats are covered by (?:(?:[a-
z]{1,2}\d{1,2}|[a-z]{2}\d[a-z]|[a-z]\d[a-z]). Within this, there are three possibilities for the first part before the blank: The
first being a combination of 1-2 letters and 1-2 digits (LN, LLN, LNN or LLNN), the second being 2 letters, 1 digit and 1
letter (LLNL), and the third being 1 letter, 1 digit and 1 letter (LNL). The end of the string must always be NLL which is
taken care of by the sub expression \d[a-z]{2}))$.
Note that not all letters are valid in all positions, so this regular expression will accept some invalid postal codes, but it
will at least help the respondent to comply with the basic format of the postal codes.
Exercise 9:

- 214 -
Forsta Confidential Forsta v2022 Scripting Manual

Make a script to validate a US zip code. Question ID: zipcode. US zip codes are 5 digit codes. So it is tempting to set
up a numeric question with total digits 5, and let the default validation do the work. However, the first number can be a
zero (0), and to make sure that it is not removed when the value is stored (as it would for numeric questions), the
question should be set up as an open text question with field width 5 instead of as a numeric. The easiest way to
validate that all 5 characters are digits, is to use a Regular Expression.
The answer is given in APPENDIX A Answers to Exercises.

14.5. The Array Object


The Array object has been used previously in the manual. There are two types of arrays – typed arrays and JScript
arrays (see Arrays on page 39 for more information). The methods and properties here can be used on both types.
Typed arrays can be declared as below:
var arrayName : type[] = [value0, value1, …, valuen]
or
var arrayName : type[arrayLength];
or
var arrayName : type[];
arrayName = new type[arrayLength];
JScript arrays can be declared as follows:
var arrayName = [value0, value1, …, valuen]
or
var arrayName = new Array(value0, value1, …, valuen);
or
var arrayName = new Array();
or
var weekday = new Array(arrayLength);
The Array Object has one property, the length of the array (number of items in the array):
arrayName.length
The methods of the Array object are described in this section.

14.5.1. Combining Arrays


arrayName.concat({item1{, item2{, . . . {, itemN}}}})
concat returns a new array consisting of a combination of arrayName and any other supplied items. The items to be
added (item1,...,itemN) to the array are added, in order, from left to right. If one of the items is an array, its
contents are added to the end of arrayName. If the item is anything other than an array, it is added to the end of the
array as a single array element.

Combining arrays with codes answered on two questions into one array
If you have two multi questions and would like to create an array consisting of all the codes answered on the two multi
questions, one possible way is to combine the two arrays you get from the categories method:
var q8 = f('q8').categories();
var q9 = f('q9').categories();
var codes = q8.concat(q9);

14.5.2. Converting Arrays to Strings


array.join(separator)

- 215 -
Forsta v2022 Scripting Manual Forsta Confidential

join returns a string value consisting of all the elements of an array concatenated and separated by the specified
separator character. If separator is omitted, the array elements are separated with a comma. If any element of the
array is undefined or null, it is treated as an empty string ("").
array.toString()
array.valueOf()
Both toString and valueOf converts elements of an array to strings. The resulting strings are concatenated, separated
by commas. This is the same as using join without specifying a separator (or specifying comma as separator).

Converting an Array to a String with Line Breaks between Elements


This example is similar to using categoryLabels to list the answers to a multi question and include them in an email
text (see String Object Methods that Use Regular Expression Objects on page 213 for more information). Instead of
the default commas between the items listed in the array returned from categoryLabels, we want line breaks. If
the email is sent as plain text, you then have to replace the commas with the special character \n.
This script will convert the array to a string and use line breaks as delimiter between the elements of a multi question
brands:
var body : String = "";
body += "Here are the answers on the brands question:\n\n"

var brandsAnswers = f("brands").categoryLabels();


brandsAnswers = brandsAnswers.join("\n");

body += brandsAnswers

SendMail("[email protected]",f("email"),"Answers",body);
If the mail is sent as HTML, you must replace the commas with the HTML <br> tag:
var body : String = "";
body += "Here are the answers on the brands question:<br><br>"

var brandsAnswers = f("brands").categoryLabels();


brandsAnswers = brandsAnswers.join("<br>");

body += brandsAnswers

SendMail("[email protected]",f("email"),"Answers",body,"","",0,0)
;

14.5.3. Removing and Adding Elements


array.pop( )
pop removes the last element from an array and returns it. If the array is empty, undefined is returned.
array.push({item1 {item2 {... {itemN }}}})
push appends new elements (item1,...,itemN) to an array, and returns the new length of the array. The push
method appends elements in the order in which they appear. If one of the arguments is an array, it is added as a
single element. Use the concat method to join the elements from two or more arrays.
array.shift( )
shift removes the first element from an array and returns it.
array.unshift({item1{, item2 {, ... {, itemN}}}})
unshift returns an array with specified elements (item1,...,itemN) inserted at the beginning. The items will
appear in the same order in which they appear in the argument list.

14.5.4. Changing the Order of the Elements


array.reverse()

- 216 -
Forsta Confidential Forsta v2022 Scripting Manual

reverse returns an Array object with the elements reversed. The method reverses the elements of the Array
object in place (array). It does not create a new Array object during execution. If the array is not contiguous, the
reverse method creates elements in the array that fill the gaps in the array. Each of these created elements has the
value undefined.
array.sort({this.sortFunction})
sort returns an Array object with the elements sorted. sortFunction is optional and is the name of the function
used to determine the order of the elements. Because Forsta script nodes are wrapped inside a class, you have to
use the keyword this to refer to the current instance (this.sortFunction). If the sorting function is omitted, the
elements are sorted in ascending, ASCII character order. The sort method sorts the Array object in place; no new
Array object is created during execution.
If you supply a function in the this.sortFunction argument, it must return one of the following values:

• A negative value if the first argument passed is less than the second argument.
• Zero if the two arguments are equivalent.
• A positive value if the first argument is greater than the second argument.

Validating Grid with "Other, specify" Alternatives


Assume you have a grid q1 with two "other, specify"-items:

In a question such as this, the "other, specify" items will usually not be required, whereas the remaining items will be
required. To achieve this, we must set the "Not required" property on the grid question, and provide our own validation
code instead.
There should also be validation checking that text is provided if a rating is provided for an "other, specify" field and
vice versa. For this, the standard "Other Specify Checking" can be used (just ensure it is turned on when generating
web interview files). However, if the respondent accidentally rates one of the "other" items, there is no way for the
respondent to unselect that row. We must therefore include a removal of the radio button selection for the "other"
items when they are not answered correctly.
Here is the answer list of this question with codes used:

- 217 -
Forsta v2022 Scripting Manual Forsta Confidential

Below is a validation code that can be used on such a question:


var form = f("q1");
var codes = a("q1").diff(set("97","98")).members(); //all codes except
"other"

var codes = codes.sort(this.NumSort); //sort the codes so the items are


checked in the same order as they are displayed

var notAnswered = new Array(); //array to hold text of not answered items

for(var i : int = 0;i<codes.length;i++)


{
var code = codes[i];
if(!form[code].toBoolean())
{
//add the label of not answered element to the array:
notAnswered.push(form[code].label());
}
}

codes = new Array("97","98"); //codes of "other, specify"-elements

for(i=0;i<codes.length;i++)
{
code = codes[i];
if(form[code].toBoolean() && !f("q1_"+code+"_other").toBoolean())
{
//remove answer
form[code].set(null);
}
}
if(notAnswered.length > 0)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please answer for all providers.
Answers are missing for:<br>"+notAnswered.toString());
}
//helper function for sorting
function NumSort(a,b)
{
var x = parseInt(a,10);
var y = parseInt(b,10);
return x-y;
}

- 218 -
Forsta Confidential Forsta v2022 Scripting Manual

This example uses the push method to add elements to the end of an array. We use the sort method to sort the
array. When the codes array is set with the statement
var codes = a("q1").diff(set("97","98")).members();
it is built from set expressions, and as we have learnt the order of the items within a set is insignificant. So the order
the elements come in the array after using this expression is not necessarily the same order as in the answer list. To
make sure we get them in the same order as in the answer list, so the listing in the error message does not become
confusing to the respondents, we use the sort method with the helper function NumSort that converts its parameters
(the codes in the array) to numbers and then do subtraction and return the result. If the result is negative, the first
code is less than the second, if it is 0 they are equal and if the result is positive the first one is greater than the
second. This is just as the description of the sortFunction above.

14.5.5. slice and splice


array.slice(start, {end})
slice returns a section of an array. start is the index to the beginning of the specified portion of the array. end is
optional and is the index to the end of the specified portion of arrayObj. The slice method copies up to, but not
including, the element indicated by end. If start is negative, it is treated as length+start where length is the
length of the array. If end is negative, it is treated as length+end where length is the length of the array. If end is
omitted, extraction continues to the end of arrayObj. If end occurs before start, no elements are copied to the
new array.
array.splice(start, deleteCount, {item1{, item2{, ... {,itemN}}}})
splice removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted
elements. start is the index from which to start removing elements. deleteCount is the number of elements to
remove. item1,..., itemN are optional elements to insert into the array in place of the deleted elements.
The splice method modifies array by removing the specified number of elements from position start and inserting
new elements. The deleted elements are returned as a new Array object.

- 219 -
Forsta v2022 Scripting Manual Forsta Confidential

15. Customizing Standard Error Messages


We have seen numerous examples on how to add your own validation code to your surveys. This chapter looks into
how you can add your own texts to the standard answer checks that are provided in Forsta.
The following standard answer checks (validations) are available in Forsta:

• Answer required checks - All questions (except for ordinary multi questions without an exclusive item ("None
of the above")) are by default required. You can set a question to be "Not required" in the properties of the
question, or you can turn off the checking for all questions by deselecting "Answer required checks" when
generating WI.
• Exclusivity tests - An "exclusive item" in the answer list of a multi question is an answer alternative with the
"single punch" property set. (Typically a "None of the above" or "Don't know" answer alternative.) This means
that the answer alternative cannot be answered in combination with any of the other items. The exclusivity
check makes sure that the question has at least one answer, and that no exclusive item is selected in
combination with other answers. This checking can be turned off by deselecting "Exclusivity tests" when
generating WI.
• Other-specify checking - When the "other" property is set for an item in an answer list, a text box is included
next to that item. The "other-specify" checking makes sure that there is a correspondence so that the text box
has an answer only if that answer alternative is selected and visa versa. It can be turned off globally by
deselecting "Other-specify checking" when generating WI.
• Rank order tests - For a ranking question or a grid question with the "ordered" property set, the system
checks that the answers constitute a set of consecutive integers starting at 1, and that all items have a rank.
This default checking can be turned off globally by deselecting "Rank order tests".
• Answer size tests for fixed-width fields - If a field width is defined for a question, the system checks that the
respondent's answer is within the limit. This cannot be turned off globally, because the database is set up
according to the field width definitions, so the database cannot accept answers above this limit.
• Numeric validation - For numeric and numeric list questions, the system checks that the answer consists of
the symbols 0 to 9 only, and is within the limits defined in total digits, decimal places as well as lower and
upper limit. This validation cannot be turned off globally because the database is set up according to these
settings and cannot accept non-numeric answers that do not correspond to these settings.
All of these types of validation have their own error messages provided in Forsta. These error messages are provided
in a number of languages, but are the same for all users of an installation. They can be changed globally on a Forsta
server installation, but not for individual surveys.
If you want something other than the standard error messages, you must add code in the validation code field of the
question where the validation applies. This chapter explains a number of functions that make it easier to build
customized error messages for the default answer checks.

15.1. Functions for Standard Validation


The following functions can be used to find out if any of the standard validation in Forsta has found an error in the
respondent's answer(s):

Function Description
QuestionErrors()
returns true if an error has been raised during any validation, false otherwise.
MissingRequiredError()
returns true if one or more required answers to a question are missing, false
otherwise.
ExclusivityError()
returns true if an exclusive answer ("single punch") in a multi has been selected
together with any other alternative, false otherwise.

- 220 -
Forsta Confidential Forsta v2022 Scripting Manual

NotSpecifiedError()
returns true if an alternative in an Other-Specify construct has been
selected/answered without filling in the associated "Specify" text box, false
otherwise.
NotSelectedError()
returns true if a "Specify" value has been entered in the text box of an Other-Specify
construct without selecting/answering the associated alternative, false otherwise.
RankError()
returns true if the "Ordered" property has been selected for the form and the
answers to the questions are non-numeric, do not start at 1 or are non-consecutive,
false otherwise.
SizeError()
returns true if one or more open-ended answers exceeded the maximum length
specified in field width, false otherwise.
NumericError()
returns true if the “Numeric” property has been selected and the answer is not
numeric, false otherwise.
PrecisionError()
returns true if the “Numeric” property has been selected and the answer cannot be
stored within the defined total digits, false otherwise.
ScaleError()
returns true if the “Numeric” property has been selected and the answer contains
more decimals than in the defined decimal places, false otherwise.
RangeError()
returns true if the “Numeric” property has been selected and the answer is outside
the defined range, false otherwise.
PasswordError() used on a opentext panel variable with the password property set. Returns true if
any of the password validation settings for the panel (in panel settings) have not
been satisfied.

Example:
if(MissingRequiredError())
{
SetQuestionErrorMessage(LangIDs.en,"Please provide an answer.");
}
When one of these functions returns true, an error situation has already been flagged, so you do not have to use the
RaiseError function.

15.2. Template Based Error Messages


The system allows you to use templates for your error messages in custom validation. For each error type, various
elements are filled in that can improve the information content of the messages you report to the
respondents. Instead of simply using fixed strings for error messages, the ErrorTemplate function can be used to
“plug in” information about the current question, like question texts, current answers etc.
ErrorTemplate(spec)
spec is a string with the template specification. Inside the spec string you may use different elements that are singled
out with caret (^) as pre- and suffix, e.g.
^MISSING^
Example:
SetQuestionErrorMessage(LangIDs.en, ErrorTemplate("^MISSING^ has not been
answered."));
This will set the text of the error message to "label(s) has not been answered"

- 221 -
Forsta v2022 Scripting Manual Forsta Confidential

Templates are available for all the standard validation. There are usually several versions of the templates, which
differ in how they separate words when they are listed. Some only use commas, some use commas, but "and" or "or"
between the last two items. "and"/"or" is also available in several languages, so e.g. in German they will be replaced
with "und"/"oder" and so on.

15.2.1. Answer Required Checks


MissingRequiredError()
returns true when one or more required answers to a question are missing. The following template elements can be
used when MissingRequiredError returns true:

Template Description
MISSING
Labels of all questions that lack answers, comma separated.
MISSING_AND
Same as above, but with the word “and” separating the two last items.
MISSING_OR
Same as above, but with the word “or” separating the two last items.

Example:
if(MissingRequiredError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please select an answer for ^MISSING_AND^."));
}

15.2.2. Exclusivity Tests


ExclusivityError()
returns true if an exclusive answer ("single punch") in a multi has been selected together with any other alternative.
The following template elements can be used when ExclusivityError returns true:

Template Description
SEL_EXCL
The labels of all exclusive (single punch) answers that were selected.
SEL_EXCL_AND
Same as above, but with the word “and” separating the two last items.
SEL_EXCL_OR
Same as above, but with the word “or” separating the two last items.
SEL_NEXCL
The labels of all non-exclusive (multi punch) answers that were selected.
SEL_NEXCL_AND
Same as above, but with the word “and” separating the two last items.
SEL_NEXCL_OR
Same as above, but with the word “or” separating the two last items.
DEF_EXCL
The labels of all exclusive (single punch) answers, regardless of which of them that were
selected.

- 222 -
Forsta Confidential Forsta v2022 Scripting Manual

DEF_EXCL_AND
Same as above, but with the word “and” separating the two last items.
DEF_EXCL_OR
Same as above, but with the word “or” separating the two last items.
DEF_NEXCL
The labels of all non-exclusive (multi punch) answers, regardless of which of them that
were selected.
DEF_NEXCL_AND
Same as above, but with the word “and” separating the two last items.
DEF_NEXCL_OR
Same as above, but with the word “or” separating the two last items.

Examples:
if(ExclusivityError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please do not check ^SEL_EXCL_OR^ if you check other
answers to the question."));
}

if(ExclusivityError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("^DEF_EXCL_AND^ can not be combined with any of the other
answers."));
}

15.2.3. Other-Specify Checking


Note: These two functions will ONLY work when the option “Other-Specify checking: Check that BOTH
checkbox and textbox have been completed for an Other-specify answer” has been selected in survey
settings.

NotSpecifiedError()
returns true if an alternative in an Other-Specify construct has been selected/answered without filling in the associated
"Specify" text box.
NotSelectedError()
returns true if a "Specify" value has been entered in the text box of an Other-Specify construct without
selecting/answering the associated answer alternative.
The following template elements are defined when one of these functions returns true:

Template Description
OTHER
Label of the alternative/input that requires specification in an Other-Specify construct.
SPEC
The specification

Examples:

- 223 -
Forsta v2022 Scripting Manual Forsta Confidential

if(NotSpecifiedError())
{
SetQuestionErrorMessage(LangIDs.en,ErrorTemplate("Please specify if
^OTHER^ is chosen."));
}
if(NotSelectedError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("If you specify ^OTHER^ then please select the ^OTHER^
option."));
}

15.2.4. Rank Order Tests


RankError()
returns true if the "Ordered" property has been selected for the form and the answers to the questions are non-
numeric, do not start at 1 or are non-consecutive. The following template elements are defined when RankError
returns true:

Template Description
RANK_MIN
The label of the first member of the ranking scale, or 1 if the question is open ended.
RANK_MAX
The label of the nth member of the ranking scale, or n if the question is open ended, where n is
the number of items to rank.

Example:
if(RankError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please enter consecutive answers in the range ^RANK_MIN^
to ^RANK_MAX^."));
}

15.2.5. Answer Size For Fixed-Width Fields


SizeError()
returns true if one or more open-ended answers exceeds the maximum length specified in the field width. The
following template elements are defined when SizeError returns true:

Template Description
TOO_LONG
The labels of the inputs that were too long.
TOO_LONG_AND
Same as above, but with the word “and” separating the two last items.
MAX_SIZE
The maximum allowed size.

Example:

- 224 -
Forsta Confidential Forsta v2022 Scripting Manual

if(SizeError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("The answers to ^TOO_LONG_AND^ were longer than
^MAX_SIZE^ characters and have been truncated. Please review."));
}

15.2.6. Numeric Validation


NumericError()
returns true if the "Numeric" property has been selected and the answer is not numeric. The following template
elements are defined when NumericError returns true:

Template Description
NUMERIC_ERRORS
The labels of all elements with a numeric error.
NUMERIC_ERRORS_AND
Same as above, but with the word “and” separating the two last items.

Example:
if(NumericError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please make sure that the answers to ^NUMERIC_ERRORS^
are numbers only."));
}

15.2.7. Precision Error Tests


PrecisionError()
returns true if the "Numeric" property has been selected and the answer cannot be stored within the defined total
digits. The following template elements are defined when PrecisionError returns true:

Template Description
PRECISION
The defined total digits
PRECISION_ERRORS
The labels of all elements with a total digits error.
PRECISION_ERRORS_AND
Same as above, but with the word “and” separating the two last items.

Example:
if(PrecisionError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please enter a number with no more than ^PRECISION^
digits for ^PRECISION_ERRORS^."));
}

- 225 -
Forsta v2022 Scripting Manual Forsta Confidential

15.2.8. Scale Error Tests


ScaleError()
returns true if the "Numeric" property has been selected and the answer contains more decimals than in the defined
decimal places. The following template elements are defined when ScaleError returns true:

Template Description
SCALE
The defined decimal places
SCALE_ERRORS
The labels of all elements with to many decimals.
SCALE_ERRORS_AND
Same as above, but with the word “and” separating the two last items.

Example:
if(ScaleError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please enter answers with no more than ^SCALE^ decimals
for ^SCALE_ERRORS_AND^."));
}

15.2.9. Range Error Tests


RangeError()
returns true if the "Numeric" property has been selected and the answer is outside the defined range. The following
template elements are defined when RangeError returns true:

Template Description
RANGE_MIN
The label of the defined minimum value.
RANGE_MAX
The label of the defined maximum value.
RANGE_ERRORS
The labels of all elements with too many decimals.
RANGE_ERRORS_AND
Same as above, but with the word “and” separating the two last items.

Example:
if(RangeError())
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please enter answers in the range ^RANGE_MIN^ to
^RANGE_MAX^."));
}

- 226 -
Forsta Confidential Forsta v2022 Scripting Manual

Note: If the survey is using a responsive layout, the client-side validation (which does not have details of
numeric range boundaries) is executed before any custom validation. These template elements will therefore
not function and the default error messages will be presented.

15.2.10. Columns in 3D grid


In 3D grids the CTITLE primitive is available to give the possibility of including the column header (question text) of the
question in the error message.

Template Description
CTITLE
The column header (question text) for the question in the 3D grid.

Example:
if(f("q1").size() < 5)
{
SetQuestionErrorMessage(LangIDs.en,
ErrorTemplate("Please select at least 5 items for ^CTITLE^."));
}

- 227 -
Forsta v2022 Scripting Manual Forsta Confidential

16. Useful ASP.NET Intrinsic Objects


This chapter contains examples of some ASP.NET objects that you may find useful in your scripts, with examples of
how they can be used. It is not intended as a comprehensive description of them. For more information, consult an
ASP.NET reference manual.

16.1. Request
Information can be sent in to the server from the user either from a web form (as the questions in the survey), passed
in with the web address URL or stored in a cookie. This, as well as other information about the incoming request can
be retrieved using the Request object.
We will look into some of the properties of the Request object. All of these return values of the type
NameValueCollection. This is a type that represents a sorted collection of associated String keys and String
values that can be accessed either with the key or with the index (integer from 0). This means that their values can be
referenced in the same way as you refer to values in an Array (see Arrays on page 39 for more information), but also
using their String key, for example:
var aValue = Request("arg");
This will look through all values sent in with the request to find a key that matches the name specified in argand
return the corresponding value. If there is no match for arg, null will be returned. This means that you can use the
expression
Request("arg")!=null
to check if it exists before using the value returned.

Note: Survey links in hitlists can have parameters added to the link. Two functions are available to receive the
value from the link; Request and UserParameters (see UserParameters on page 89 for more information). The
function you must use depends on the link's “Link type” setting. Request() will only be able to retrieve the
value from the hitlist link when "Link type" in the Hitlist Field Properties page is set to "Unencrypted URL
parameters". Refer to the separate Reportal User Guide for further details.

A more robust approach than using the Request object directly is to use the separate properties of the Request
object to prevent naming conflicts. In the next chapters we will describe some of the most useful properties.

Note: Request and Request.Form are not supported by CAPI or AskMe App. Use RequestForm (see
RequestForm on page 228 for more information).

16.1.1. Request.Form
Request.Form
will give the collection of form values submitted using "POST".

16.1.2. RequestForm
RequestForm
This was created because Request.Form and Request are not supported by CAPI or AskMe App. RequestForm
functions in the same way as Request.Form (see Request.Form on page 228 for more information).

16.1.3. QueryString
Request.QueryString()
will give the collection of values supplied on the URL or from a form submitted with "GET". If you want to send values
into the survey with the url, they can be included after the question mark after project_ID.aspx, separated by
ampersands (&), e.g.
http://survey.confirmit.com/wix/project_ID.aspx?variable1=value1&variable2
=value2
The keys here are variable1 and variable2, so using the key variable1 as in

- 228 -
Forsta Confidential Forsta v2022 Scripting Manual

Request.QueryString("variable1")
with the url above will return the value value1.

16.1.4. Request.Cookies
Request.Cookies
will return the cookies stored from the of the Forsta server domain. It returns an HttpCookieCollection object (see
Cookies on page 232 for more information).

16.1.5. ServerVariables
Request.ServerVariables
will give the information sent in the header or internal server values.
Here is a table listing an extract of the possible server variables in the collection returned from the
ServerVariables property:

Variable Meaning
ALL_HTTP
All HTTP headers sent by the client., with their names capitalized and
prefixed with HTTP_

ALL_RAW
Retrieves all headers in raw form (the form they were sent to the
server by the client).
CONTENT_LENGTH
The length of the content as given by the client.
CONTENT_TYPE
The MIME type of the request, such as www-url-encoded for a form
being posted to the server.
GATEWAY_INTERFACE
The Common Gateway Interface (CGI) supported on the server.
HTTP_<HeaderName>
The value stored in the header HeaderName. Any header other than
those listed in this table must be prefixed by HTTP_ in order for the
ServerVariables collection to retrieve its value. Note that the server
interprets any underscore (_) characters in HeaderName as dashes in
the actual header. For example if you specify HTTP_MY_HEADER,
the server searches for a header sent as MY-HEADER.
HTTP_ACCEPT
The MIME types the client can accept.
HTTP_ACCEPT_LANGUAGE
The languages accepted by the client.
HTTP_ACCEPT_ENCODING
The compression encoding types supported by the client.
HTTP_CONNECTION
Indicates whether the connection allows keep-alive functionality.
HTTP_COOKIE
Returns the cookie string that was included with the request.

HTTP_USER_AGENT
Returns a string describing the browser that sent the request. See
below for an example.

- 229 -
Forsta v2022 Scripting Manual Forsta Confidential

HTTP_HOST The host name of the server.

HTTPS Returns "On" if HTTPS was used for the request and "Off" if not.

HTTPS_KEYSIZE
Number of bits in the encryption used to make the HTTPS connection.
For example, 128.
HTTPS_SECRETKEYSIZE
Number of bits in server certificate private key. For example, 1024.
HTTPS_SERVER_ISSUER
Issuer field of the server certificate.
HTTPS_SERVER_SUBJECT
Subject field of the server certificate.
LOCAL_ADDR
The IP address of the server which is handling the request.
QUERY_STRING
Query information stored in the string following the question mark (?)
in the HTTP request.
REMOTE_ADDR
The IP address of the remote host making the request.
REMOTE_HOST
The host name of the client making the request, if available.
REQUEST_METHOD
The type of the HTTP request made: "GET", "POST" or "HEAD".
SERVER_NAME
The server's host name,
SERVER_PORT
The port number to which the request was sent.
SERVER_PORT_SECURE
A string that contains either 0 or 1. If the request is being handled on
the secure port, then this will be 1. Otherwise, it will be 0.
SERVER_PROTOCOL
The HTTP protocol and version in use on the server.
SERVER_SOFTWARE
The name and version of the web server software running on the
server.

Sending in Values with the URL


Assume you have a pop-up survey that is triggered from pop-up scripts on several sites. You want to identify which
site the respondents were surfing when the pop-up appeared. In the pop-up scripts you should use different survey
links for the different sites, as below:
http://survey.confirmit.com/wix/<project ID>.aspx?site=1
http://survey.confirmit.com/wix/<project ID>.aspx?site=2
http://survey.confirmit.com/wix/<project ID>.aspx?site=3
http://survey.confirmit.com/wix/<project ID>.aspx?site=4
Insert a hidden single question source in your questionnaire. The answer list should have the different sites you use
and codes that correspond to the values you use in the URLs, for example:

- 230 -
Forsta Confidential Forsta v2022 Scripting Manual

To set this hidden question based on the values sent in with the URL, use the code given below in a script node at the
beginning of the questionnaire.
f("source").set(Request("site"));
Alternatively, you can use the QueryString property:
f("source").set(Request.QueryString("site"));

Important
The script node with Request must be the first node in the questionnaire, because once the respondent
moves to the next page, the values are lost.

Now source can be used for reporting, quotas, logic etc. in the same way as an ordinary question.

Recording respondent's browser version and operating system


The system does not automatically save information about the respondent’s user agent (browser version and type and
operating system (OS)) into a survey. To get this information you must add a check function into the survey at a
location before your respondents start to provide answers. For this you can use the function
Request.ServerVariables("HTTP_USER_AGENT"). This will contain information about the respondent application
name and version and the operating system.
If you have a hidden open text question with question id UserAgent, then the script will look like this:
var agentInfo = Request.ServerVariables("HTTP_USER_AGENT");
f("UserAgent").set(agentInfo);
Variable UserAgent will then contain string values that will look like this:
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/52.0.2743.116 Safari/537.36
More information about the different values returned can be found here: https://msdn.microsoft.com/en-
us/library/ms537503(v=vs.85).aspx

16.2. Response
Response is used to write content to the client (the respondent's browser), including headers and cookies. Here we
will only cover the Write method and the property used to set cookies.

16.2.1. Write
Response.Write(arg)
You may use the Write method for debugging purposes, for example to get values of variables you are using in your
script written to the screen when testing to help identifying why the script does not work as intended. For other
purposes it is recommended to use response piping with ^-s inside one of the text fields of a question or an info
instead, since you will then have better control of where on the page the text you output is placed.
arg can be any type of object, as it will be converted to a string when written to the client.

- 231 -
Forsta v2022 Scripting Manual Forsta Confidential

16.2.2. Cookies
Response.Cookies
The Cookies property indicates the cookies collection, which allows addition of cookies to the outgoing stream,
adding cookies to the client from a Forsta survey. It can for example be used to prevent respondents of an open
survey from taking the survey more than once, as showed in the example below.
The class HttpCookiesCollection provides a wrapper for a collection of cookies. You use this to set and modify
properties and values in the cookies. Most useful for us is the Add method:
cookiesCollection.Add(ccokie)
The Add method allows the addition of a single cookie to the collection. The parameter cookie is an object of the
HttpCookie class. HttpCookie has two different constructors:
varcookie = new HttpCookie(string);
which creates and names a new cookie.
varcookie = new HttpCookie(string1, string2);
which creates, names (string1), and assigns a value (string2) to a new cookie.
There is currently a problem with the JScript.NET compiler that gives a type mismatch error when compiling with an
HttpCookie object. For this reason the variable should be defined as Object to avoid this checking:
var cookie : Object = new HttpCookie(string);
or
var cookie : Object = new HttpCookie(string1, string2);
Here are the most relevant properties of HttpCookie:
cookie.Expires
The Expires property indicates the expiration date and time of the cookie, as a .NET DateType value (a bit different
than the JScript .NET Date object. Consult a .NET reference for more details.) After this expiration date and time, the
cookie will not be sent with the request, so you can not retrieve it anymore.
cookie.Name
Name indicates the name of the cookie.
cookie.Path
Cookies are specific to the site they originate from, so client browsers only send cookies to the DNS domain from
which they were created – i.e. a www.microsoft.com cookie can not be picked up by survey.confirmit.com. But you
can set a cookie to indicate the directory path on the domain that should receive it using the Path property. Using a
Path of "/" indicates that all directory paths on the server should have access to the cookie.
cookie.Value
The Value property indicates the value for the cookie.
The majority of cookies are used as a single name and value. However, a cookie can have more than one value. The
Values property allows you to set several values and also retrieve them again as a NameValueCollection:
cookie.Values
Here is an example on how to set a cookie:
var myCookie : Object = new HttpCookie("LastVisit");
var now : DateTime = DateTime.Now; //current time

myCookie.Value = now.ToString(); //convert to string


myCookie.Expires = now.AddMonths(6);
myCookie.Path = "/";
Response.Cookies.Add(myCookie);
The value of the cookie can later be fetched like this:

- 232 -
Forsta Confidential Forsta v2022 Scripting Manual

var myCookie : Object = Request.Cookies("LastVisit");


if(myCookie != null)
{
var last = myCookie.Value;
//The variable last will now have the timestamp of the last access
}

Using Cookies to Limit Access to an Open Survey


Sometimes the sample for a survey is not known in advance, so that you can not set up the survey as a limited survey
with cryptic, individual links. Then you have to distribute the open link to the survey instead. However, you can use
cookies to try to prevent the respondents from answering more than once. This is not a bullet-proof method of course,
because respondents may have set their browsers to not accepting cookies, they may delete cookies and they may
also respond from different PCs,
You can set the cookie from a script node anywhere in the survey depending on how far you think the respondents
should have answered before not being allowed to reenter. A cookie using the project id as name can be set with this
script:
var interval = 3;
var expiry = new Date();
expiry.setMonth(expiry.getMonth()+interval);

var objCookieObject : HttpCookie;


objCookieObject = new HttpCookie(CurrentPID());
objCookieObject.Value = "true";
objCookieObject.Expires = expiry.getVarDate();
objCookieObject.Path = "/" ;
Response.Cookies.Add(objCookieObject);
In the beginning of the survey you may then have a condition that uses this expression to check if the cookie is
present:
Request.Cookies[CurrentPID()] != null
If we also wanted to check the value we would also add that to the expression (not really necessary in this scenario):
Request.Cookies[CurrentPID()] != null &&
Request.Cookies[CurrentPID()].Value == "true"

- 233 -
Forsta v2022 Scripting Manual Forsta Confidential

17. Scripting in Reportal


The Reportal scripting capability enables developers to leverage the power of Reportal with greater flexibility for report
interface customization. Scripting functionality is added to Reportal to enable the user to, for example:

• Perform custom permission control.


• Build aggregated table definitions based for example on user information (e.g. enduser role or company) or
parameter values (e.g. selected project and question/question type).
• Build the domain (valid values) of parameters dynamically.
• Mask a parameter domain dynamically, based for example on information about the user (usertype, company
or role).
• Send email.
The target audience for using Reportal Scripting is developers familiar with programming in Microsoft developer tools.
The scripting Language is Microsoft JScript.NET.
A syntax highlighter is enabled by default in all areas in Reportal where scripts can be written (see The Syntax
Highlighter on page 12 for more information). If the BETA CodeCompletion component is not enabled, this syntax
highlighting will be used. When the syntax highlighter is in use, each time the Tab key is pressed, the current line of
script is indented one step. Each press of the Shift-Tab keys removes one indent from the line. Note that the Tab key
does not insert a tab in the text. To disable the syntax highlighting, in Survey Designer, go to the Design page > Item
Editor menu and uncheck the “Syntax highlighting in editors” box. Refer to the Survey Designer User Guide for further
details.

17.1. Where is Scripting Used in Reportal?


You can add scripts to a range of elements at various levels in Reportal:

• Report level - at the Report Level you can define your Permission script and implement common functions
available in a Codelibrary script.
• Page level - at the Page level you can add a script that runs once the report page is submitted. This script is
primarily used to validate values and combinations of values in input controls on the page. You can also use
scripting to hide a page from, for example, a particular role.
• Parameters - parameters have domain scripts, mask scripts and filter summary scripts.
• Visual Components - all visual components have a Hide expression. Additionally, component definitions for
the following components can be changed dynamically using a render script:
o Tables
o Charts
o Gauges
o Verbatim Tables
o Texts
o Hit Lists
o Admin menu
o Admin menu-like options in navigator
• Filters - filter expressions can be built dynamically from a script by adding Filter Scripts within the Filter
Toolbox.

17.2. Caching of Tables


Using aggregated tables in data sources containing large data-sets will degrade performance. In Reportal,
performance is improved by caching the data-sets used by the tables, and in View mode all tables are cached by
default (tables are not cached in Preview mode).

- 234 -
Forsta Confidential Forsta v2022 Scripting Manual

Performance of affected tables can however be significantly improved. It is possible to explicitly enable caching for
scripted tables by adding the following code to the table script:
table.Caching.Enabled = true;
table.Caching.CacheKey = "X"; //can use any string value
This code will function for most scripted tables. The table cache will then take into account any context that may affect
the table, for example filters, report base, parameters and benchmark, and will cache different versions of the table for
every variation of these. So even if the script modifies these properties, caching can still be enabled.
The table.Caching.CacheKey property can be used if you want to explicitly control the cache criteria for a table.
This might be useful if the table is likely to vary by factors other than the properties mentioned above. Note that this
property is not optional, so it must be set to a string value even when it is not used. The same value can be used for
all tables.
To check whether caching will function for a table, enable caching and verify that the table dynamics (for example
report base, filters, drilldowns etc.) still function correctly in View mode.

Note: It is possible to disable caching by setting table.Caching.Enabled=false in the table script.

Important
Caching should be used whenever possible as it will improve performance and take load off the system.

17.3. General Concepts


The following sections outline the concepts used in Reportal scripting.

17.3.1. Accessing Survey Content


There are two main approaches that can be used to retrieve Survey content, for example questions, ids, answers,
texts etc. when scripting in Reportal:

• Access the Report’s data source,


• Access a Project’s definition.
In addition it is possible to access tables in Database Designer.

17.3.2. Methods
report.DataSource - provides access to the project(s) defined in the Report’s data source. The input parameter is the
data source nodeid(s).
confirmit.GetProject - provides access to a project by using the Project Id as input to the GetProject method.
confirmit.GetDBDesignerSchema - by using the schemaid as input to the GetDBDesignerSchema you can access
information in Database Designer tables. The content of Database Designer tables can be used to mask or populate
dynamic lists, or control access to various components of your report.

17.3.3. Guidelines
The parameter type Project in Reportal allows you to use projects that are not in the Reportal data source . This may
be useful if you have a portal that is used for new projects that are added on a regular basis. In this case there are
three things you must do:

1. Add projects to the domain of a project parameter from the parameter domain script.
2. Grant users access to "your" (report designer's) projects.
3. Explicitly grant access to projects from the report permission script.
When granting users access to your projects, it is important that sufficient access measures are included in the
permission script to avoid unintentional access to variables in the projects that are available from the code.

- 235 -
Forsta v2022 Scripting Manual Forsta Confidential

17.3.4. Question Category


To combine multiple questions in a project into different categories, each question in a survey can be defined to
belong to one or more Question Categories. The Question Category can be used to display the questions in a drop-
down menu, grouped by the defined Category, as shown in the example. Note that this is a way to group your
questions by category, and no calculations will be applied to your questions by category.

Figure 8 Example of the Question Category drop-down

To set this up, you must first create a resource survey which will hold the question categories. Proceed as follows:

1. Create a project in Professional Authoring, and insert a single question type which can be called Categories.
2. Enter the different categories in the Answers tab.

Figure 9 The Resource survey

When the resource survey is in place, you can define in your projects which category the questions belong to.

3. Under Question Properties for your Grid, Multi or Single question, you have a Question Category field. Enter
into this field the code of the Category to which the question is to belong. Note that if a question is to belong to
several categories, you must enter the codes separated by semi-colons. Ensure there are no spaces between
the categories and semi-colons.

- 236 -
Forsta Confidential Forsta v2022 Scripting Manual

Figure 10 The Question Category property

When all questions have been categorized in the survey, the report can be setup.

4. Create a parameter in the Report toolbox, and name it for example p_category.

Figure 11 The Parameter

The Parameter Values folder for this parameter should be empty.

5. Under Properties, set the Type to Fixed Questionnaire Element.

Figure 12 The Parameter properties

You must now script the functionality for this parameter.

6. Right-click on the p_category element and select Script. Enter a customized script based on the following:

Figure 13 Example of the Category script

- 237 -
Forsta v2022 Scripting Manual Forsta Confidential

The GetProject method, will take in as a parameter either the data source name (which is named
resource_survey in the example), or the project id. The GetQElementsGroupedByCategory method will take in
as parameters the defined resource project, the question id of the categories question. The third parameter is
a Boolean, where you can select if the Grid questions included in a parameter should be collapsed or
expanded.
When the Parameter is in place, it must be included in a List element. The List element can be included on a
Query report page where the report viewer can select a report query.

7. Drag the p_category parameter to the List object.

Figure 14 The Parameter in the List object

8. Right-click on the List object, and select Properties, then set up the properties as required.

Figure 15 The List properties

The List properties are as follows:

• Type - defines the List type you would like to display.


• Auto Submit - should be selected if there are other elements on the page that depend on the selection made
on in this List. The page will then refresh when a selection is made.
• Auto Complete - includes a type-in-box, where the letters you type in will display the list that matches.
• If Type (above) is set to Drop-down, you can add an Empty Row which will be shown by default before a
selection is made; check the box as required.
• List Style - defines the style of the list frame.
• Items Style - is the style of the elements within a Category.
• Group Headers Style - is the style of the Header elements in your List.

- 238 -
Forsta Confidential Forsta v2022 Scripting Manual

17.3.5. The Role Column


A Role column is included in maintenance screens for Reportal end-users and panelists. This column enables you to
allocate a role to a user or panelist, giving you another method of specifying access to the report.

Note: The only place this role can be used is within Reportal scripts, by calling the user.HasRole method.

17.4. Script Types


The script types available in Reportal Scripting are described in the following sections. For each of the script types the
following structure is used:

• Where do I find the script editor for this script?


• What’s the main purpose of this script?
• Short description of the script type.
• Some simple examples of the script type.
For a full list of all methods, the Reportal Scripting Object Model is described in the document “Reportal Scripting”.
You can download this from the User Manual page in the Forsta Extranet (http://extranet.confirmit.com).

17.4.1. Report Level Scripts


Report Level scripts comprise:

• Code Library scripts


• Permission script

17.4.1.1. Codelibrary Script

Editor: Main purpose:


Report Menu > Codelibrary Script Write common script classes available from any other scripts in the
report. Multiple Codelibrary scripts can be added to a report, stored
in the Codelibrary Script folder node in the Report toolbox. Many
classes can be added to each script.

Description:
In this script you can write your own classes. These classes will typically be used as follows:
• When you have some common logic that should be used from several of the other scripts in the report.
• When the logic in a hide script is too complex to be expressed in an expression, you can implement this logic
in a common class and just call this method from the hide script.
If you want to use any of the objects available in other scripts, you must pass them as parameters to the
code library script.
To add a new script, in the Report toolbox right-click on the Codelibrary Script folder node and select
Add Codelibrary Script.

Example - Codelibrary:
class MyLib
{
__function MultiplyBy100(value : Decimal) : Decimal
__{

- 239 -
Forsta v2022 Scripting Manual Forsta Confidential

____return value * 100;


__}
}

Example - Use the library in a Text component:


if(!state.Parameters.IsNull("p_decimal"))
{
var lib : ReportCommon.MyLib = new ReportCommon.MyLib();
var val : Decimal = state.Parameters.GetDecimal("p_decimal");
output.Append(lib.MultiplyBy100(val));
}

All Codelibrary scripts will be stored in the Codelibrary Script folder node in the Report toolbox.

17.4.1.2. Permission Script

Editor: Main purpose:


Permissions > Permission Script Validate that the current user really has permission to all current
values of all parameters. Can also be used to initialize required
values for report parameters.

Description:
This script is always called first for each page in the report and before exporting any object to MS Office or other
format for that report.
Even though you for example mask content of a parameter used in a dropdown to limit the user’s access to specific
values, you should also write a permission script taking care of the permission control, for the following reasons:
• Even though input controls are masked, hostile users may try to hack the report using a tool to post other
values to the input controls.
• If a report user for example has access to a specific parameter value on a certain point of time, he can save a
page with the given value to one of his private folders (Viewer Presentation component). As report designer,
you may want to revoke this access at some point of time. If so, the permission script will deny this user
access to the previously saved page.
In some cases you may want to design a report using projects that are not in the report data source. This may be the
case if you are continuously making new projects available to a report and do not want to modify the report and re-
publish it each time. Two steps are required to achieve this:
1. Go to the Viewer Project Permission page and grant access to projects outside data source.
2. Explicitly grant access to required projects in this script.
If you like to initialize or change parameter values based on other parameter values, this can also be done in this
script. Alternatively use the page script for this. These two scripts are the only scripts where you are allowed to
change parameter values.

Example - Allow access to project not in datasource:

- 240 -
Forsta Confidential Forsta v2022 Scripting Manual

// Authorizes project outside datasource


state.AuthorizeProjectAccess("p0559090");

Example – Raise permission denied:


var unit : String = state.Parameters.GetString("p_unit");
if(user.UserId == "someuser" && unit != "someunit")
HasPermission = false;

Example – Derive a parameter from another


if(state.Parameters.IsNull("p_project"))
state.Parameters["p_question"] = null;

17.4.2. Page Level Scripts


Page Level scripts comprise:

• Page Validation scripts


• Page Hide scripts
To access the Page Script functionality:

1. Right-click on the report page in the Report toolbox and select Script from the drop-down menu.
The Page Script page opens.

- 241 -
Forsta v2022 Scripting Manual Forsta Confidential

Figure 16 The Page Script page

2. Type the required script into the appropriate field, compile to test it, and save.

Note: All visual components on a page that have Hide scripts also have a Hide script in the Report Master.

17.4.2.1. Page Validation Script

Editor: Main purpose:


Report Tree > Page > Script Validate the inputs made on the page and stop users from
moving to other pages if input is not valid.

Description:
Some pages that you design in Reportal may sometimes have several input controls. Sometimes, it may be
required to validate the combination of values in these controls. That should be done from this script.
Add all validation errors into the validation error collection in the pageContext object. Then use these values
from one or more Text controls to output these messages.
If the validation error collection has any items, Reportal will stop any navigation away from this page.

Example – Validate a page:

- 242 -
Forsta Confidential Forsta v2022 Scripting Manual

if(page.IsSubmit)
{
if(state.Parameters.IsNull("p_date_1")||state.Parameters.IsNull("p_date_2")){
this.pageContext.ValidationErrors.Add("Please fill both dates");}
else{var d1 : DateTime = state.Parameters.GetDate("p_date_1");
var d2 : DateTime = state.Parameters.GetDate("p_date_2");
if(d2 < d1)
{
this.pageContext.ValidationErrors.Add("End date should after start date");
}
}
}

Example – Write validation error message from a Text component


for(var s in pageContext.ValidationErrors)
output.Append(s + "<br>");

17.4.2.2. Page Hide Script


You can use this functionality to hide a report page or a visual component on a page from, for example, a specific role.
If the expression in the Hide Script field evaluates to TRUE, the page will be hidden.

Note: All visual components on a page that have Hide scripts also have a Hide script in the Report Master.

A possible scenario could be that you wish to selectively hide a report page based on the viewer's role. Note that you
set the viewer's role in a text field under Enduser Permissions - refer to the separate Reportal User Guide for further
details.
For this example assume that you have a number of end users. Some have the role of "Manager", while the others
have the role of "Consultant". Assume you have created a page that you wish to be accessible only to those with the
Manager role and you want to hide it from the end users with the Consultant role.

1. Right-click on the page in the Report toolbox and select Script from the drop-down menu.
The Page Script page opens, with the Hide Script field towards the top.

Figure 17 The Hide Script field

2. In the Hide Script field, enter the script user.HasRole("Consultant").

Figure 18 The script

- 243 -
Forsta v2022 Scripting Manual Forsta Confidential

For the managers this script will evaluate to FALSE, so they will be able to see the page. However for the
consultants it will evaluate to TRUE, so the page will be hidden.

17.4.3. Parameter Scripts


Parameter scripts comprise:

• Domain script
• Mask script
• Filter Summary script

17.4.3.1. Domain Script

Editor: Main purpose:


Report tree > A Parameter > Script > Domain Load the domain for a parameter.

Description:
Script used to build up the domain for a parameter. Without scripting, the domains for parameters are loaded
different ways depending on parameter type:
Projects - Connect the parameter to a question in a survey containing the project IDs that you want to load.
Double-click the parameter to open the page where you can connect the project to a question.
Questionnaire Elements - Manually build a hierarchical structure of questionnaire elements from the parameter
designer page (double-click parameter to get there).
Segments - Do it the same way as for questionnaire element, except that you drag segments into the tree
structure.
String Response - Connect parameter to a question the same way as for the project parameters. This makes the
domain implicitly load the answer list of that question.
If you use a domain script for a parameter, you override the default way of loading the domain. You have to do this
loading explicitly from within the script.
The advantage is that you can then load the domain differently, for example depending who the user is and what
other selections the user has made for other parameters. Typically, you can do this based on the user’s role or
some other information from a database designer table relating user’s to elements in lists.

Projects Example:
To tie one or more projects to a report, include a parameter to your report.
1. Under parameter properties, select Type Project.
2. Right-click on the parameter, and select Script.
3. To include projects to your report, add the following script:
var p : Project = this.confirmit.GetProject('pxxxxxxx');
parameter.Items.AddProject(p);
p = this.confirmit.GetProject('pxxxxxxx');
parameter.Items.AddProject(p);
4. In the GetProject method, include the id of your project.
5. To use this parameter, include a List element in your report.
6. Drag & drop the Questionnaire Elements Example project parameter.

- 244 -
Forsta Confidential Forsta v2022 Scripting Manual

The Questionnaire Elements can be used to include questions from a project into a drop-down menu. If you
have several projects in your report, you can script which questions to display depending on the project
selected in the project parameter (p_project).
7. Create a new parameter and rename it for example p_questions.
8. Right-click on it and select Script, then enter the following code:
if(state.Parameters.IsNull("p_project"))
return;
//Checks to see if a project has been seleced. If not, nothing is
returned.

var pid : String = state.Parameters.GetProjectId("p_project");


var project : Project = confirmit.GetProject(pid);
//The project selected is defined

var questions : Question[] = project.GetQuestions();


parameter.Items.AddQuestions(questions);
//The questions in the project selected are included in the parameter.
If you do not wish to include OpenText and MultiOpen questions in the parameter, since these will not work
in Aggregated Tables, the following code can be used instead of the last line;
parameter.Items.AddQuestions(questions);
for(var i : int=0; i<questions.length;i++)
{
if (questions[i].QuestionType != QuestionType.OpenText &&
questions[i].QuestionType != QuestionType.MultiOpen)
parameter.Items.AddQuestions(questions[i]);
}
This script will iterate through the questions, and check if they are QuestionType OpenText or MultiOpen. If not,
they will be added to the questions parameter.

17.4.3.2. Mask Script

Editor: Main purpose:


Report tree > A Parameter > Script > Mask Mask the domain of a parameter.

Description:
For these types of parameters, you can add a mask script to mask the parameter domain for example based on other
selections. This script is typically used when the original domain can be loaded the default way, but the list of values should
be masked in some way.
You can choose whether to use inclusive or exclusive masks, i.e. whether the keys you add to the mask are
those that should be included in or excluded from the domain.
Mask script only applies to project, segment questionnaire element and string response parameter types.

Example – Removing a question from domain:


mask.Access = ParameterAccessType.Exclusive;
mask.Keys.Add("q4");

- 245 -
Forsta v2022 Scripting Manual Forsta Confidential

17.4.3.3. Filter Summary Script

Editor: Main purpose:


Report tree > A > Script > Filter summary Customize the filter summary label of a parameter.

Description:
For some parameters it will make sense not to have one line in filter summary for each parameter. For example, if you use
one parameter to choose which question to filter by, and another to select the filter values.
In these cases you can choose to hide one of the parameters from the filter summary and customize your own label for the
other one to have the filter on one line.

Example – Customize filter summary for filter:


if(state.Parameters.IsNull("p_filter_q") ||
state.Parameters.IsNull("p_filter"))
return;
var q : QuestionnaireElement = state.Parameters["p_filter_q"];
state.LoadParameterLabel("p_filter_q");
state.LoadParameterLabel("p_filter_a");
output.Append(q.Label + "(");
var first : boolean = true;
for(var r : ParameterValueResponse in a)
{
if(first)
first = false;
else
output.Append(", ");
output.Append(r.Label);
}
output.Append(")");

17.4.4. Component Scripts


All visual components in Reportal have a "hide" expression. If this expression evaluates to true for a component, then
this component is hidden from the report viewer. Additionally some components have "render" scripts used to
dynamically modify the properties for the component before the component is rendered/displayed.
Note that you can use the CTRL+S keyboard shortcut to save changes when writing component scripts.

17.4.4.1. Render Scripts


Render scripts can be defined for the visual component types, to set properties for the components dynamically.

17.4.4.2. Hide Expression Script


Used to dynamically hide or show visual components on a report page.

Editor: Main purpose:


Report tree > A Component > Script > Hide Hide a Reportal component conditionally. All components in Reportal
can include a Hide expression.

Description:

- 246 -
Forsta Confidential Forsta v2022 Scripting Manual

A typical Hide expression could for example check whether or not a parameter is null. If more complex logic is required,
consider using a script library function to implement this logic.

Example - Checking parameter:


state.Parameters.GetString("p_show_hide") == "hide"

Example – Calling a library function


new ReportCommon.MyLib().DoHide(state.Parameters)

Note: All visual components on a page that have Hide scripts also have a Hide script in the Report Master.

17.4.4.3. Aggregated Table Script

Editor: Main purpose:


Report tree > A Table > Script > Render Dynamically change the aggregated table based on for example
parameter values or user information.

Description:
Use this script to dynamically add, remove or change headers for aggregated tables. If a table already has a banner or a
parameter header, this script is called after the banner header is substituted with the header from within the banner and the
parameter headers are substituted with a header for the current value for that parameter.

Example – Changing numbers of decimals:


if(!state.Parameters.IsNull("p_table_dec")
{
var pv : ParameterValueResponse = state.Parameters["p_table_dec"];
table.Decimals = pv.NumericValue;
}

Example - Adding a header:


var hf : HeaderFormula = new HeaderFormula();
hf.Type = FormulaType.Expression;
hf.Expression = "4";
table.RowHeaders.Add(hf);

Example – Changing a header:


var hf : HeaderFormula = table.RowHeaders[0];
hf.Expression = "9";

- 247 -
Forsta v2022 Scripting Manual Forsta Confidential

Note: If you add a script to a table, caching is disabled for that table (see Caching of Tables on page 234 for
more information).

17.4.4.4. Verbatim Table Script

Editor: Main purpose:


Report tree > A Table > Script > Render Dynamically change the verbatim table based on for example
parameter values or user information.

Description:
Most typical use of this script would be to dynamically set the questionnaire element of the table based on a parameter, but
you can also change other properties of the verbatim table.

Example – Set questionnaire element:


var q : QuestionnaireElement = state.Parameters["p_question"];
verbatimTable.QuestionnaireElement = q;

Example – Set sorting property:


verbatimTable.Sorting = VerbatimSortingType.RespondentId;

17.4.4.5. Chart Script

Editor: Main purpose:


Report tree > A Table > Script > Render Dynamically change the chart based on parameter values or user
information.

Description:
One way of using charts scripts is to allow the report user to decide dynamically the chart type and set the chart type based
on a parameter in a script.
If you set up a report in which the user can choose which question is to be used in tables and possibly also add one or more
questions to the column headers, you may have to implement some logic regarding the parts of a table that are to be
included in the chart.

Example – Setting chart type:

- 248 -
Forsta Confidential Forsta v2022 Scripting Manual

if(!this.state.Parameters.IsNull("p_chart_type"))
{
var ct : String = this.state.Parameters.GetString("p_chart_type");
switch(ct)
{
case "pie":
chart.Series.SeriesDefault.ChartType = ChartTypes.Pie;
chart.SeriesInRows = true;
break;
case "column":
chart.Series.SeriesDefault.ChartType = ChartTypes.Column;
break;
case "bar":
chart.Series.SeriesDefault.ChartType = ChartTypes.Bar; break;
}
}

Example – Setting part of table:


chart.RowHeaderMask.AddHeader("benchmark");

17.4.4.6. Gauge Script

Editor: Main purpose:


Report tree > A Gauge > Script > Render Dynamically change the gauge based on parameter values or user
information.

Description:
In this script you can add, remove or change exactly the same values as you can modify in the gauge style designer and
gauge designer.

Example – Changing size of an existing circular gauge:


var cg : CircularGauge = gauges.GetGauge("Gauge1");
cg.Size.Height = 50;
cg.Size.Width = 50;

17.4.4.7. Hit List Script

Editor: Main purpose:


Report tree > A Hit List > Script > Render

- 249 -
Forsta v2022 Scripting Manual Forsta Confidential

Dynamically change the Hit List based on for example parameter


values or user information.

Description:
In this script you can add, remove or change columns of the Hit List, and you can change the properties of the Hit List itself.

Example – Adding a column:


var column : HitListColumn = new HitListColumn();
column.QuestionnaireElement = state.Parameters["p_question"];
hitlist.Columns.Add(column);

17.4.4.8. Text Script

Editor: Main purpose:


Report tree > A Table > Script > Render Dynamically set the text of a Text component based for example on
parameter values or user information.

Description:
If a Text component has a script, any text set in the property sheet of the component will be overwritten. If your report is
multilingual, you must also check the current language of the report to add the proper texts. One workaround for this may
be to add your dynamic texts to an answer list in a multilingual survey and get the texts by using the project.GetQuestion()
and question.GetAnswer methods.

Example – Add some text:


if(report.CurrentLanguage == 9)
text.Output.Append("XXX");
else if(report.CurrentLanguage == 20)
text.Output.Append("YYY");

Example – Add some text based on an answer text:


var p : Project = report.DataSource.GetProject("ds0");
var q : Question = p.GetQuestion("q_text");
var t : Answer = q.GetAnswer("text1");
text.Output.Append(t.Text);

17.4.5. Filter Scripts

- 250 -
Forsta Confidential Forsta v2022 Scripting Manual

Editor: Main purpose:


Filter tree > Insert a filter script > Script Dynamically create a filter expression.

Description:
Build your filter expression dynamically based on parameter values. Expression syntax is the same as for
regular filter expressions.

Example – Setting filter expression:


filter.Expression = "gender = \"male\"";

17.5. Validation
To avoid publishing reports that contain errors, Reportal has built-in features to verify that no scripts contain syntax
errors.
On preview and compilation of a report, if script errors are found, an error frame will appear showing a list of the
errors. The list contains links that lead to the page where the error is located. There is also a Debugging tab in the
frame which will contain a list of any debugging errors found during preview.

1. To access the Validation functionality without publishing the report, go to the Report > Quality Control >
Validate Report menu command or enter an element containing a script and choose Compile from the menu.
Reportal will start to run through the script(s) checking the code. A new pane opens in the lower-right part of
the window, displaying the message “Please wait, loading list…”. Once the checking process is finished, any
errors discovered will be displayed in the pane.
The Question ID column displays the question ID or the script ID where the error is located. The Error column
provides a short summary of the error type.

2. Click the error link to open the erroneous script, in the frame above the error pane.
Any errors are stored from when a report is published to the next time it is published, and from preview to
preview. This applies to both Runtime and Validation errors.
You can at any time view a list of any errors that may have been discovered. Go to the Report > Quality Control
menu command and select Validation Errors, Runtime Errors or Debug Errors as appropriate. Note that these are
three tabs on the same page, so you can easily switch from one to the other.

- 251 -
Forsta v2022 Scripting Manual Forsta Confidential

18. Testing Survey Scripts


All scripts should be carefully tested before setting a survey live. Forsta provides a few helpful tools to use when
testing scripts.

18.1. Testing in Professional Authoring


The following sections provide some guidelines for testing in Professional Authoring. For further information, refer to
the separate Survey Designer user guide.

18.1.1. Check Script Code


In Professional Authoring, use the Check Script Code functionality to check for syntax errors in your script code. A
check is also performed automatically when you launch the survey in test or production mode, but using this
functionality gives you a faster way of checking the syntax because you do not have to generate the database and
interview files.

Typical syntax errors that may be found using the script checker are referencing undeclared variables and functions,
brackets that do not match - [ ], { } or ( ) - and similar.
The errors found will be listed at the bottom of the screen, and by clicking each error you can open the script node,
question or condition containing the error.

18.1.2. Manual Testing


Professional Authoring offers two ways of manually testing the surveys. The first of these, Quick Test, allows you to
open the survey within Professional Authoring at the question you select.

- 252 -
Forsta Confidential Forsta v2022 Scripting Manual

"Quick Test" compiles the survey code and runs it locally on your PC without writing data back to a database. Data is
just kept in the current session. To recompile after making changes, choose the "with rebuild" option. "New
respondent" removes the data kept in the session so that you will restart on a blank survey. Quick test is perfect to
use when debugging scripts because the fact that it is does not generate a database makes it fast. This means you
can make small changes to a script and test them immediately with Quick Test (with rebuild).
If you need the test responses to be stored in a database, you can launch the survey in test mode and run the test
interview. Refer to the separate Professional Authoring user guide for further details.

18.1.3. Random Data Generator


You may have scripts that are syntactically correct, but which will fail run-time. For example, this could be non-existing
question ids as parameter in the f function or trying to set a string value in a numeric question. Often these errors
happen only for certain combinations of answers. To be able to test out as many combinations as possible, you can
use the Random Data Generator functionality. This is a Forsta add-on. If you do not have access to this functionality,
please contact your Forsta account manager for more information.)
The Random Data Generator lets you run a number of automated test interviews with randomly selected responses.
All script code in script nodes, masks, conditions, validation code and response piping will be executed, and any script
errors will be recorded and listed for inspection at the end of the RDG run.

The list of errors from the random data generator is clickable, and clicking on the description will open the script,
question or info where the error appeared.

- 253 -
Forsta v2022 Scripting Manual Forsta Confidential

In the example above, the problem is that the input to the Math.max method is not a list of numbers. In the code
above that method returns NaN (not a number), which makes the script fail when attempting to set the question max,
which has the numeric property. A better solution would be to use the Forsta Max function (see Max and Min on page
77 for more information), which automatically converts the values to numbers before finding the maximum.
To help debugging you can use the results tab on the questions to see top line results for each question. It is also
possible to filter these results so that you see the results only for those that got a particular error by clicking the filter
icon in the rightmost column. You can also click the link in the "Test" column to access the first interview that
experienced the error.

18.1.4. Tips for Debugging


This section contains a few tips to assist you while debugging problem code.

18.1.4.1. Response.Write
It can sometimes be difficult to find out why a script is failing. In these cases it can help to use the
Response.Write() method to output some variables to the screen. For example, in the script above which failed
when trying to set the max question, we could comment out the last line and instead output the max variable to
screen:
var max = Math.max(f("q4").values());
Response.Write("Max="+max);
//f("max").set(max);
The text from the Response.Write call will appear at the top of the page before any interview HTML. The result
from the script above will look something like this:

If an error appears inside of a loop statement, it often helps to use Response.Write to help identify in which iteration
the script fails:
for(var i : int = 0; i<codes.length; i++)
{
Response.Write("i = "+i+"<br>");
< ... >
}
Other tricks to simplify debugging is to use /* and */ to comment out part of the code to help identify exactly where
the error occurs. This can be done as a "binary search": First you comment out ½ of the code in a script. If the error
still occurs, you know that it is in the other half. Then you can comment out half of that section – and so on.
It can also be very helpful to use Top line reporting or the "results" tab on a question, the "Edit" functionality under
"Survey Data" or doing a data export of the responses with "error" status to look into what answers actually are stored
in the question(s) involved in the script code.

18.2. Testing in Survey Designer


You can test your survey without having to generate a database, allowing you to perform manual tests while avoiding
time-consuming database generations.

The Test survey button and menu


Click the Test survey button in the toolbar to start the test at the beginning of the survey. Once the test system in
running you can jump to any question by clicking on the desired question or node in the Survey pane. Click the Test
survey down-arrow to open a menu of options.

- 254 -
Forsta Confidential Forsta v2022 Scripting Manual

• Test - new respondent - this mode clears any answers you may already have added to the survey in previous
tests, and runs the survey.
• Test - same respondent - if you have already run a test and then perhaps made some changes to a question,
using this test mode means any answers you have already added to the survey are remembered. You will then
be able to move quickly through the survey to the question you wish to view, without having to add all the
answers again.
• Generate external test - an externally accessible test link to the survey is generated, and you can then make
this link available to people who do not have a Forsta User login.
• View warnings and errors - in the event errors are found when the test is run, these will be listed on the
Warnings and Errors page until the errors are rectified. Select this option to view the list, and click on an error
in the list to go to the question containing the error.
When you select Test - new respondent or Test - same respondent, the survey loads and opens at the first
question in the main area of the screen as the respondent would see it. Note that the Survey pane changes color to
pale blue to indicate you are in the Test mode.
Note also that the system will remember which test mode you last used for this survey. If you wish to use the other
mode then you must change the mode using the drop-down menu.

Testing only a specific question


If you wish to test only a specific question, in the Survey pane move the pointer over the desired item and click its
overflow icon to open the drop-down menu. he Test with new respondent and Test with same respondent options
open the test functionality at the selected question. Once the test functionality is running, you can move through the
survey as a respondent will be able to.

Testing for different modes


In the event you have selected more than one rendering mode in the Overview > Settings area, you can change the
display mode for the survey test. You can then see how the survey will look to respondents using the various modes
you have selected. To change the mode, in the Test area toolbar click the Mode button to open the drop-down menu,
then select the desired display mode.

Testing for different languages


If your survey is multilingual, then you can select which language you run the test in. To change the language, in the
Test area toolbar click the Language button to open a drop-down menu of the languages available, then select the
desired language.

Additional Options
A number of additional options are available while testing - in the Test area toolbar click the Options icon to open a
drop-down menu. Here you can select whether you wish to view background questions, panel questions and/or
hidden questions while you are testing. Note that these settings only apply whilst you are in the test mode; they will
not have any effect on the production survey. Your selections will be remembered and applied whenever this survey is
in Test mode.
For further information, refer to the separate Survey Designer user guide.

- 255 -
Forsta v2022 Scripting Manual Forsta Confidential

19. Programming Conventions


Programming conventions are important to programmers because they make scripts easier to read and understand.
Writing scripts that are easy to understand will make searching for errors easier, and will make it easier to re-use
scripts. If programmers agree on a common way of writing scripts, it will be much easier to read the scripts of other
programmers. Even the programmer that originally wrote a script may have problems understanding his or her own
code after a few months unless it is written and commented in a way that makes it easy to read.

19.1. Comments
It is recommended to make extensive use of comments in your scripts. They will help you and others to more quickly
understand the way your code works and how to use it (see Comments on page 15 for more information).

19.2. Naming Conventions


When naming variables and functions, always try to use as descriptive names as possible. If an array holds the codes
from a question, call it something like codes or q1Codes or similar, not just e.g. a. Similarly, a function that copies a
multi question should be called something like CopyMulti, not f1. There is no point in making short names in JScript
.NET.
A variable name must start with a lower or upper case letter or underscore, and continue with letters, digits or
underscore. However, it is recommended to follow the following naming conventions:

• variable names and names of methods and properties should start with a lowercase letter in the first word. The
next words should open with an uppercase letter. Examples: gridCodes, availableCodes, randomNumber,
indexOuterLoop.
• function names and names of objects should start with an uppercase in the first word, and have uppercase
letters in the beginning of all subsequent words. Examples: CopyMulti, SelectItems, CalculateAverage.

19.3. Spaces and Line Breaks


Except from within string expressions, you can use line breaks and spaces as much as you like when writing JScript
.NET code. Use these to make your code easier to read. Add spaces between different parts of your scripts, and use
line breaks in if-then-else constructs and loops to make it easier to understand the routing in your scripts.
while (condition)
{
<statements>
if(condition)
{
<statements> }
else
{
<statements>
}
<statements> }
With a structure like this it is easier to see where the then- and else-branch of the if-condition ends, and which
statements belong to the various parts.

19.4. Curly Brackets


It is recommended that you always use the curly brackets ({ and }) in the if, switch, while, do while, for and function
statements. If you have just one statement inside the curly brackets, they are optional, but it is recommended that you
make it a rule to always use them, limiting the possibility of making mistakes.
Example:
if(condition)
<statement1>;
is the same as

- 256 -
Forsta Confidential Forsta v2022 Scripting Manual

if(condition)
{
<statement1>;
}
so you may find it convenient to drop the curly brackets. But you may soon need to add another statement. If you add
it like this:
if(condition)
<statement1>;
<statement2>;
or
if(condition)
<statement1>; <statement2>;
it will be equivalent to
if(condition)
{
<statement1>;
}
<statement2>;
This will be very different from
if(condition)
{
<statement1>;
<statement2>;
}

19.5. Semi Colon


Statements are separated with semi colon (;) in JScript .NET. However, if you have line breaks between the
statements, the semi colon is not required. However, it is recommended to always use it anyway, in case a line break
is removed. You may have observed that all examples in this documentation use semi colons between the
statements.
However, when working with the if, switch, while, do while, for and function statements you have to be careful with the
semi colon. For example, remember that the while statement includes the statements within the curly brackets. If you
place a semicolon just after the condition, like this:
while (condition); { <statements> }
you will actually end up with a loop that never terminates. The semicolon will be interpreted as the end of an empty
statement. It will be this empty statement that will be executed until the condition is false, not the statements within the
curly brackets. The code that executes will be similar to this:
while (condition) { }<statements>
The condition is likely never to return false, since no statements are executed. This means that the loop will never
terminate. This will cause a time-out for the respondent. But notice that there are no syntactical errors in the script, so
you will not receive any error message on the script as such.

19.6. The Step by Step Approach


It is possible to do a lot of operations in one long statement. However, this makes the scripts hard to read.
Compare for example the following code, which randomly picks one of the codes in an array codes,
selectedCode = codes[Math.floor(Math.random()*codes.length));
with this code:
randomNumber = Math.random()*codes.length;
randomIndex = Math.floor(randomNumber);
selectedCode = codes[randomIndex];

- 257 -
Forsta v2022 Scripting Manual Forsta Confidential

The first code will be a bit more efficient than the latter, because you do not have to store values in the variables
randomNumber and randomIndex. However, because it will be much easier to understand what happens in the last
one, that approach is recommended.
To increase readability, use temporary variables and do the calculations step by step.

19.7. Writing Efficient Code


Below are a few tips on how to write code that is efficient:

• Define types on your variables, constants and functions when possible.


• Always make sure that the script does not run through unnecessary iterations in a loop, or unnecessary
statements in an iteration. Use break or continue to terminate or skip to the next iteration.
• If you need to call the f function for the same question more than once in a script, store it in a variable and
refer to that variable instead.
• Avoid using calls to user-defined functions in code masks. Set a hidden multi question instead and refer to it
with the f function.
• Use methods of the form objects like domainValues and categories when possible instead of hard coding
codes(1,2,3,…) in your scripts.
• Use short-circuiting evaluations in expressions involving logical and (&&) and or (||): Place conditions most
likely to be true first for the logical or (||) operator, and conditions most likely to be false first for the logical
and operator (&&).
• Only use local variables in functions (use the var keyword).

- 258 -
Forsta Confidential Forsta v2022 Scripting Manual

20. Differences between JavaScript and JScript


There are a number of areas within Forsta where JavaScript can be used instead of JScript.Net. This chapter lists the
differences between the two scripts and provides examples of usage.
A survey-level setting must be enabled to allow use of the JavaScript engine. The setting is located on the Survey
Settings > General Options tab. When this setting is enabled JavaScript can operate in all channels (CAWI, CAPI,
CATI, Self-completion/AskMe App). When the JavaScript engine is enabled, all script input areas (script nodes,
masking, validation etc...) display a text box stating that the JavaScript engine is in use.

Note: For Offline Apps (CAPI, AskMe, the JavaScript engine MUST be used.

Note: Try-catch blocks must not be used in JavaScripts as errors will then be created.

20.1. Syntax and Behavior Differences

JScript.NET code example JavaScript code example Comments


toString() for enums
DeviceType.toString() == "Desktop" DeviceType.toString() == "1" returns it's integer
DeviceType == "Desktop" DeviceType == "Desktop" value, not name.

SurveyArrayList no
f('q1').values().toString() == "1, 2" f('q1').values().toString() == "System.Object[]" longer exists, so
^f('q1').values()^ returns "1,2" ^f('q1').values()^ returns "System.Object[]" standard .NET array is
used. String
representation of
standard .NET types
cannot be changed.
item() instead of .NET
f('q1')['1'] f('q1').item(1) indexer [].
f('q1')('1') f('q1').item(1)
f('q1').get_Item('1') f('q1').item(1)
Request.Form['q1'] Request.Form.item('q1')
Request.QueryString["test"] Request.QueryString.item('test')
UserParameters[paramName] UserParameters.item(paramName)

N/A .NET CLR types not


var h = new Hashtable() supported.
DateTime.Now
HttpContext.Current.Response

No strict types
var o : Date = new Date() var o = new Date() declaration.
function ImagenesURL():String { function ImagenesURL() { return '' }
return '' }

var s = new Set() var s = set()


var s = new SurveyArrayList() var s = []
var h = new Hashtable() var h = {}

- 259 -
Forsta v2022 Scripting Manual Forsta Confidential

Jscript.NET JavaScript Comments


Catching try { f('invalid-question-id') } f('invalid- JavaScript engine invocation exception cannot
exceptions catch { } question-id') be caught.

Differences between Jscript.Net code and JavaScript code for Offline Mobile Apps (CAPI, AskMe):

Jscript.NET code JavaScript code Comments


Referencing a COMPOUND f(‘Q1’)[‘2’] == ‘1’ f(‘Q1’).item(‘2’) == ‘1’ Differences:
question code: f(‘Q1’)[‘2’].set(‘1’) f(‘Q1’).item(‘2’).set(‘1’) item() instead of .NET
indexer []
Numeric lists and use of SUM(f(‘Q1’)) SUM(f(‘Q1’).values()) Differences:
.values() SUM(f(‘Q1’).values()) .values() now required
Creating a set object var s = new Set() var s = set()
Creating an array var a = new var a = ['1','2','3','9','10'];
Array(1,2,3,9,10);

20.2. Usercode API Function Declaration Changes


The following sections list the usercode AIP Function Declaration changes.

20.2.1. Standard Code


Difference table

Note: Any methods and properties not listed here are the same for both scripts.

JScript.NET function JavaScript function


GetCatiRespondentUrl(String questionId, params
string[] @params) GetCatiRespondentUrl(String questionId)
GetCatiRespondentUrl(String questionId, string[] @params)

GetRespondentUrl(String questionId, params String[]


params) GetRespondentUrl(String id)
GetRespondentUrl(String id, Boolean isCallBlock, String
userParameter, String[] params)

UserParameters[paramName] UserParameters.item(paramName)
SetPanelistCredit(Int32 credit, String comment, String SetPanelistCreditBySectionId(Int32 credit, String comment,
sectionId) String sectionId)
SetPanelistCredit(Int32 credit, String comment, Int32 SetPanelistCreditByPanelistId(Int32 credit, String comment,
panelistId) Int32 panelistId)
SetPanelistCreditWithCustomVariables(Int32 credit, SetPanelistCreditWithCustomVariablesBySectionId(Int32
String comment, String sectionId, String[] fieldNames, credit, String comment, String sectionId, String[] fieldNames,
String[] fieldValues) String[] fieldValues)
SetPanelistCreditWithCustomVariables(Int32 credit, SetPanelistCreditWithCustomVariablesByPanelistId(Int32
String comment, Int32 panelistId, String[] fieldNames, credit, String comment, Int32 panelistId, String[] fieldNames,
String[] fieldValues) String[] fieldValues)
N/A Cookies
N/A CreateCookieObject(String name, String value)

- 260 -
Forsta Confidential Forsta v2022 Scripting Manual

IsNet(object quadIP, object quadNet, object N/A


quadMask)

20.2.2. ExprObj
Difference table:

JScript.NET example JavaScript example


exprObj["q1"] exprObj.item("q1")

20.2.3. Set
Difference table:

JScript.NET example JavaScript example


setObj["2"] setObj.item("2")

20.2.4. Request
Note: Request is only supported for online interviewing; it is not available in off-line interviewing.

JScript.NET function JavaScript function


Int32 ContentLength Int32 ContentLength
String ContentType String ContentType
NameValueCollection Form JavascriptNameValueCollection
Form
NameValueCollection Headers JavascriptNameValueCollection
Headers
NameValueCollection Params JavascriptNameValueCollection
Params
String Path String Path
String PhysicalPath String PhysicalPath
NameValueCollection QueryString JavascriptNameValueCollection
QueryString
NameValueCollection ServerVariables JavascriptNameValueCollection
ServerVariables
Uri Url Uri Url
String UserAgent String UserAgent
index[key] item(key)
Void ValidateInput() Void ValidateInput()

- 261 -
Forsta v2022 Scripting Manual Forsta Confidential

N/A
Void Abort()
Byte[] BinaryRead(Int32 count)
String[] AcceptTypes
String AnonymousID
String ApplicationPath
String AppRelativeCurrentExecutionFilePath
HttpClientCertificate ClientCertificate
Encoding ContentEncoding
HttpCookieCollection Cookies
String CurrentExecutionFilePath
String CurrentExecutionFilePathExtension
String FilePath
HttpFileCollection Files
Stream Filter
ChannelBinding HttpChannelBinding
String HttpMethod
Stream InputStream
Boolean IsAuthenticated
Boolean IsLocal
Boolean IsSecureConnection
String Item
WindowsIdentity LogonUserIdentity
String PathInfo
String PhysicalApplicationPath
String RawUrl ReadEntityBodyMode
ReadEntityBodyMode
RequestContext RequestContext
String RequestType
CancellationToken TimedOutToken
Int32 TotalBytes
UnvalidatedRequestValues Unvalidated
Uri UrlReferrer
String UserHostAddress
String UserHostName
String[] UserLanguages
Stream GetBufferedInputStream()
Stream GetBufferlessInputStream()
Stream GetBufferlessInputStream(Boolean
disableMaxRequestLength)
Void InsertEntityBody()
Void InsertEntityBody(Byte[] buffer, Int32 offset, Int32 count)
Int32[] MapImageCoordinates(String imageFieldName)
String MapPath(String virtualPath)
String MapPath(String virtualPath, String baseVirtualDir, Boolean
allowCrossAppMapping)
Double[] MapRawImageCoordinates(String imageFieldName)
Void SaveAs(String filename, Boolean includeHeaders)
String ToString()

Note: For Request.Cookies use the new Cookies object instead.

20.2.5. Response
Note: Response is only supported for online interviewing; it is not available in off-line interviewing.

- 262 -
Forsta Confidential Forsta v2022 Scripting Manual

JScript.NET function JavaScript function

Void Clear() Void Clear()


Void Close() Void Close()
Void End() Void End()
Int32 Expires Int32 Expires
NameValueCollection Headers JavascriptNameValueCollection
Headers
String Status
String Status
Void Redirect(String url)
Void Redirect(String url)
Void Redirect(String url, Boolean endResponse)
Void Redirect(String url, Boolean
Void Write(Object obj) endResponse)
Void Write(Char[] buffer, Int32 index, Int32 count) Void Write(Object obj)
Void Write(Char[] buffer, Int32 index,
Int32 count)

- 263 -
Forsta v2022 Scripting Manual Forsta Confidential

N/A
Void AddCacheDependency(CacheDependency[] dependencies)
Void AddCacheItemDependencies(ArrayList cacheKeys)
Void AddCacheItemDependencies(String[] cacheKeys)
Void AddCacheItemDependency(String cacheKey)
Void AddFileDependencies(ArrayList filenames)
Void AddFileDependencies(String[] filenames)
Void AddFileDependency(String filename)
Void AddHeader(String name, String value)
ISubscriptionToken AddOnSendingHeaders(Action`1 callback)
Void AppendCookie(HttpCookie cookie)
Void AppendHeader(String name, String value)
Void AppendToLog(String param)
String ApplyAppPathModifier(String virtualPath)
IAsyncResult BeginFlush(AsyncCallback callback, Object state)
Void BinaryWrite(Byte[] buffer)
Void ClearContent()
Void ClearHeaders()
Void DisableKernelCache()
Void DisableUserCache()
Void End()
Void EndFlush(IAsyncResult asyncResult)
Void Flush()
Boolean Buffer
Boolean BufferOutput
HttpCachePolicy Cache
String CacheControl
String Charset
CancellationToken ClientDisconnectedToken
Encoding ContentEncoding
String ContentType
HttpCookieCollection Cookies
DateTime ExpiresAbsolute
Stream Filter
Encoding HeaderEncoding
Boolean HeadersWritten
Boolean IsClientConnected
Boolean IsRequestBeingRedirected
TextWriter Output
tream OutputStream
String RedirectLocation
Int32 StatusCode
String StatusDescription
Int32 SubStatusCode
Boolean SupportsAsyncFlush
Boolean SuppressContent
Boolean SuppressDefaultCacheControlHeader
Boolean SuppressFormsAuthenticationRedirect
Boolean TrySkipIisCustomErrors
Void Pics(String value)
Void RedirectPermanent(String url)
Void RedirectPermanent(String url, Boolean endResponse)
Void RedirectToRoute(Object routeValues)
Void RedirectToRoute(String routeName)
Void RedirectToRoute(RouteValueDictionary routeValues)
Void RedirectToRoute(String routeName, Object routeValues)
Void RedirectToRoute(String routeName, RouteValueDictionary
routeValues)
Void RedirectToRoutePermanent(Object routeValues)
Void RedirectToRoutePermanent(String routeName)
Void RedirectToRoutePermanent(RouteValueDictionary
routeValues)

- 264 -
Forsta Confidential Forsta v2022 Scripting Manual

Void RedirectToRoutePermanent(String routeName, Object


routeValues)
Void RedirectToRoutePermanent(String routeName,
RouteValueDictionary routeValues)
Void RemoveOutputCacheItem(String path)
Void RemoveOutputCacheItem(String path, String providerName)
Void SetCookie(HttpCookie cookie)
String ToString()
Void TransmitFile(String filename)
Void TransmitFile(String filename, Int64 offset, Int64 length)
Void WriteFile(String filename)
Void WriteFile(String filename, Boolean readIntoMemory)
Void WriteFile(String filename, Int64 offset, Int64 size)
Void WriteFile(IntPtr fileHandle, Int64 offset, Int64 size)
Void WriteSubstitution(HttpResponseSubstitutionCallback callback)

20.2.6. Server

JScript.NET function JavaScript function


String HtmlDecode(String s) String
String HtmlEncode(String s) HtmlDecode(String s)
String UrlDecode(String s) String
String UrlEncode(String s) HtmlEncode(String s)
String
UrlDecode(String s)
String
UrlEncode(String s)

- 265 -
Forsta v2022 Scripting Manual Forsta Confidential

N/A
Void ClearError()
Object CreateObject(String progID)
Object CreateObject(Type type)
Object CreateObjectFromClsid(String clsid)
Void Execute(String path)
Void Execute(String path, TextWriter writer)
Void Execute(String path, Boolean preserveForm)
Void Execute(String path, TextWriter writer, Boolean preserveForm)
Void Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm)
String MachineName
Int32 ScriptTimeout
Exception GetLastError()
Void HtmlDecode(String s, TextWriter output)
Void HtmlEncode(String s, TextWriter output)
String MapPath(String path)
String ToString() Void Transfer(String path)
Void Transfer(String path, Boolean preserveForm)
Void Transfer(IHttpHandler handler, Boolean preserveForm)
Void TransferRequest(String path)
Void TransferRequest(String path, Boolean preserveForm)
Void TransferRequest(String path, Boolean preserveForm, String method,
NameValueCollection headers)
Void TransferRequest(String path, Boolean preserveForm, String method,
NameValueCollection headers, Boolean preserveUser)
Void UrlDecode(String s, TextWriter output)
Void UrlEncode(String s, TextWriter output)
String UrlPathEncode(String s)
Byte[] UrlTokenDecode(String input)
String UrlTokenEncode(Byte[] input)

20.2.7. NameValueCollection

JScript.NET function JavaScript function


Void Add(NameValueCollection collection) Void Add(NameValueCollection collection)
Void Add(String name, String value) Void Add(String name, String value)
Void Clear() String Get(String name) Void Clear() String Get(String name)
String[] AllKeys String[] AllKeys
String[] GetValues(String name) String[] GetValues(String name)
Boolean HasKeys() Boolean HasKeys()
String index[name] String index[name]
Void Remove(String name) Void Remove(String name)
Void Set(String name, String value) Void Set(String name, String value)
Void CopyTo(Array dest, Int32 index) N/A
String Get(Int32 index)
Int32 Count
String index[int key]
KeysCollection Keys
IEnumerator GetEnumerator()
String GetKey(Int32 index)
String[] GetValues(Int32 index)
Void Set(String name, String value)
String ToString()

- 266 -
Forsta Confidential Forsta v2022 Scripting Manual

Note: NameValueCollection may be used in RequestForm, UserParameters, Request.Form,


Reqest.QueryString, Request.ServerVariables.

20.2.8. Browser
Note: Browser is only supported for online interviewing; it is not available in off-line interviewing.

JScript.NET function JavaScript function


Boolean Beta Boolean Beta
String Browser String Browser
String Id String Id
String InputType String InputType
Boolean IsMobileDevice Boolean IsMobileDevice
Boolean JavaScript Boolean JavaScript
Boolean Tables Boolean Tables
String Type String Type
Boolean VBScript Boolean VBScript
String Version String Version
Boolean IsBrowser(String browserName) Boolean IsBrowser(String browserName)
String index[String key] String item(String key)

- 267 -
Forsta v2022 Scripting Manual Forsta Confidential

Void AddBrowser(String browserName) N/A


HtmlTextWriter CreateHtmlTextWriter(TextWriter w)
Void DisableOptimizedCacheKey()
Boolean ActiveXControls
IDictionary Adapters
Boolean AOL
Boolean BackgroundSounds
ArrayList Browsers
Boolean CanCombineFormsInDeck
Boolean CanInitiateVoiceCall
Boolean CanRenderAfterInputOrSelectElement
Boolean CanRenderEmptySelects
Boolean CanRenderInputAndSelectElementsTogether
Boolean CanRenderMixedSelects
Boolean CanRenderOneventAndPrevElementsTogether
Boolean CanRenderPostBackCards
Boolean CanRenderSetvarZeroWithMultiSelectionList
Boolean CanSendMail
IDictionary Capabilities
Boolean CDF
Version ClrVersion
Boolean Cookies
Boolean Crawler
Int32 DefaultSubmitButtonLimit
Version EcmaScriptVersion
Boolean Frames
Int32 GatewayMajorVersion
Double GatewayMinorVersion
String GatewayVersion
Boolean HasBackButton
Boolean HidesRightAlignedMultiselectScrollbars
String HtmlTextWriter
Boolean IsColor
Boolean JavaApplets
Version JScriptVersion
Int32 MajorVersion
Int32 MaximumHrefLength
Int32 MaximumRenderedPageSize
Int32 MaximumSoftkeyLabelLength
Double MinorVersion
String MinorVersionString
String MobileDeviceManufacturer
String MobileDeviceModel
Version MSDomVersion
Int32 NumberOfSoftkeys
String Platform
String PreferredImageMime
String PreferredRenderingMime
String PreferredRenderingType
String PreferredRequestEncoding
String PreferredResponseEncoding
Boolean RendersBreakBeforeWmlSelectAndInput
Boolean RendersBreaksAfterHtmlLists
Boolean RendersBreaksAfterWmlAnchor
Boolean RendersBreaksAfterWmlInput
Boolean RendersWmlDoAcceptsInline
Boolean RendersWmlSelectsAsMenuCards
String RequiredMetaTagNameValue
Boolean RequiresAttributeColonSubstitution
Boolean RequiresContentTypeMetaTag
Boolean RequiresControlStateInSession
Boolean RequiresDBCSCharacter

- 268 -
Forsta Confidential Forsta v2022 Scripting Manual

Boolean RequiresHtmlAdaptiveErrorReporting
Boolean RequiresLeadingPageBreak
Boolean RequiresNoBreakInFormatting
Boolean RequiresOutputOptimization
Boolean RequiresPhoneNumbersAsPlainText
Boolean RequiresSpecialViewStateEncoding
Boolean RequiresUniqueFilePathSuffix
Boolean RequiresUniqueHtmlCheckboxNames
Boolean RequiresUniqueHtmlInputNames
Boolean RequiresUrlEncodedPostfieldValues
Int32 ScreenBitDepth
Int32 ScreenCharactersHeight
Int32 ScreenCharactersWidth
Int32 ScreenPixelsHeight
Int32 ScreenPixelsWidth
Boolean SupportsAccesskeyAttribute
Boolean SupportsBodyColor
Boolean SupportsBold
Boolean SupportsCacheControlMetaTag
Boolean SupportsCallback
Boolean SupportsCss
Boolean SupportsDivAlign
Boolean SupportsDivNoWrap
Boolean SupportsEmptyStringInCookieValue
Boolean SupportsFontColor
Boolean SupportsFontName
Boolean SupportsFontSize
Boolean SupportsImageSubmit
Boolean SupportsIModeSymbols
Boolean SupportsInputIStyle
Boolean SupportsInputMode
Boolean SupportsItalic
Boolean SupportsJPhoneMultiMediaAttributes
Boolean SupportsJPhoneSymbols
Boolean SupportsQueryStringInFormAction
Boolean SupportsRedirectWithCookie
Boolean SupportsSelectMultiple
Boolean SupportsUncheck
Boolean SupportsXmlHttp
Type TagWriter
Boolean UseOptimizedCacheKey
Version W3CDomVersion
Boolean Win16
Boolean Win32
Version[] GetClrVersions()
String ToString()

20.2.9. JavaScriptScriptingExtensionPoint

JScript.NET function JavaScript function

IScriptCallResultCollection GetRequest(string method); JavascriptCallResultCollection GetRequest(string method)


IScriptCallResultCollection GetRequest(string method, JavascriptCallResultCollection GetRequest(string method,
int timeoutInMillisecond); int timeoutInMillisecond)

- 269 -
Forsta v2022 Scripting Manual Forsta Confidential

IScriptCallResultCollection GetRequest(string method, JavascriptCallResultCollection GetRequest(string method,


IDictionary parameters); JavascriptObject parameters)
IScriptCallResultCollection GetRequest(string method, JavascriptCallResultCollection GetRequest(string method,
IDictionary parameters, int timeoutInMillisecond); JavascriptObject parameters, int timeoutInMillisecond)
IScriptCallResultCollection PostRequest(string JavascriptCallResultCollection PostRequest(string method)
method);
JavascriptCallResultCollection PostRequest(string method,
IScriptCallResultCollection PostRequest(string int timeoutInMillisecond)
method, int timeoutInMillisecond);
JavascriptCallResultCollection PostRequest(string method,
IScriptCallResultCollection PostRequest(string JavascriptObject parameters)
method, IDictionary parameters);
JavascriptCallResultCollection PostRequest(string method,
IScriptCallResultCollection PostRequest(string JavascriptObject parameters, int timeoutInMillisecond)
method, IDictionary parameters, int
timeoutInMillisecond);

20.2.10. JavaScriptCallResultCollection

JScript.NET function JavaScript function

string this[string key] { get; } string item(string key)


Dictionary<string, string>.KeyCollection Keys { get; } string[] Keys
Dictionary<string, string>.ValueCollection Values { get; string[] Values
}
JavascriptObject GetDictionary(string key)
IDictionary<string, string> GetDictionary(string key);

20.2.11. Cookies
Note: This is a replacement for Request.Cookies. Note also that Cookies is only supported for online
interviewing; it is not available in off-line interviewing.

JScript.NET function JavaScript function


Void Add(HttpCookie cookie) Void Save*(ICookie cookie)
HttpCookie Get(String name) ICookie Get(String key)
String[] AllKeys String[] AllKeys
Int32 Count Int32 Count
this[String name] ICookie item(String key)
Void Remove(String name) Void Remove(String name)
Void Set(HttpCookie cookie) Void Save*(ICookie cookie)

- 270 -
Forsta Confidential Forsta v2022 Scripting Manual

N/A
Void CopyTo(Array dest, Int32 index)
Void Clear()
this[Int32 index]
KeysCollection Keys
IEnumerator GetEnumerator()
String GetKey(Int32 index)
String ToString()

* - You can get a cookie with the Cookies.Get method or create a new cookie with CreateCookieObject method. Note
that in either case, on completion you must save the changes with the Cookies.Save method.

20.2.12. Cookie
Note: This is a replacement for Request.Cookies. Note also that Cookie is only supported for online
interviewing; it is not available in off-line interviewing.

JScript.NET function JavaScript function


String Domain String Domain
DateTime Expires DateTime Expires
Boolean HttpOnly Boolean HttpOnly
String Name String Name
String Path String Path
Boolean Secure Boolean Secure
String Value String Value
N/A
Boolean HasKeys
this[String name]
Boolean Shareable
NameValueCollection Values
String ToString()

- 271 -
Forsta v2022 Scripting Manual Forsta Confidential

APPENDIX A: Answers to Exercises


Exercise 1:
"207 is not the same as 207, but this isn't really true"
Exercise 2:
1. x=5, y=9, z=0
2. x=5, y=9, z=8
3. x=4, y=33, z=8
4. x=35, y=35, z=8
Exercise 3:
1. Code sample 1: x=5 and y=5
Code sample 2: x=5 and y=6
2. Code sample 1: x=5 and y=5
Code sample 2: x=5 and y=5
Exercise 4:
1. f("importance")["2"].valueLabel()
2. f("importance")["2"].label()
Exercise 5:
if(!f("q2").toBoolean())
{
var codes = f("q2").domainValues();
for(var i : int = 0;i<codes.length;i++)
{
var code = codes[i];
f("q2")[code].set("3");
}
}
Exercise 6:
1,2,5,6,7,9,10,11,12

1,2,6,7,9,10,12

- 272 -
Forsta Confidential Forsta v2022 Scripting Manual

11

2,4,5,10,11

Exercise 7:

- 273 -
Forsta v2022 Scripting Manual Forsta Confidential

var d = IsDateFmt(f("date4").get(),"MM/DD YYYY");

if(!d)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Invalid date. Please correct using
the format MM/DD YYYY");
}
else
{
var dt = new Date();
dt.setFullYear(d.year,d.month-1,d.day);
var current = new Date();
if(dt.valueOf() < current.valueOf())
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please enter a date after the
current date.");
}
else if(dt.getDay() != 1)
{ RaiseError();
SetQuestionErrorMessage(LangIDs.en,f("date4")+" is not a Monday.
Please register for Mondays only.");
}
}
Exercise 8:
var num : String = f("phone").get();
var re = /^\d{3} \d{3} \d{4}$/;
if(!re.test(num))
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please provide your phone number on
the format xxx xxx xxxx");
}
Exercise 9:
var zipcode : String = f("zipcode").get();
var re = /^\d{5}$/;
if(zipcode.search(re) == -1)
{
RaiseError();
SetQuestionErrorMessage(LangIDs.en,"Please provide a valid zip code
(digits only).");
}

- 274 -
Forsta Confidential Forsta v2022 Scripting Manual

APPENDIX C: Forsta Language Codes

Important
Custom languages that are added after the initial release of Forsta are assigned a Language code number
automatically, based on the order in which the languages are added. Custom languages may therefore have
different language IDs for each installation of Forsta (On-Premise, SaaS Euro, SaaS US, SaaS AU). Therefore,
be aware that if you intend to export/import surveys between the different environments (On-
Premise/Euro/US/AU) and you are using custom languages, you should check the relevant language codes
for the sites and edit the XML export files as appropriate.

For each installation; go to the Home > Help > Language Overview menu command to view a list of the
languages, with their applicable codes, available on that server.

Language code Language Sub-name Combident

54 Afrikaans af

28 Albanian sq

1 Arabic ar

5121 Arabic Algeria ar_al

15361 Arabic Bahrain ar_ba

3073 Arabic Egypt ar_eg

2049 Arabic Iraq ar_iq

11265 Arabic Jordan ar_jo

13313 Arabic Kuwait ar_ku

12289 Arabic Lebanon ar_le

4097 Arabic Libya ar_li

6145 Arabic Morocco ar_mo

8193 Arabic Oman ar_om

16385 Arabic Qatar ar_qa

1025 Arabic Saudi Arabia ar_sa

10241 Arabic Syria ar_sy

7169 Arabic Tunisia ar_tu

- 275 -
Forsta v2022 Scripting Manual Forsta Confidential

Language code Language Sub-name Combident

14337 Arabic U.A.E. ar_ua

9217 Arabic Yemen ar_ye

43 Armenian hy

77 Assamese as

44 Azeri az

2092 Azeri Cyrillic az_cy

1068 Azeri Latin az_la

45 Basque eu

35 Belarusian be

69 Bengali bn

517 Bosnian bo

2 Bulgarian bg

3 Catalan ca

4 Chinese zh

3076 Chinese Hong Kong SAR, PRC zh_hk

5124 Chinese Macau SAR zh_ma

34820 Chinese Mandarin zh_mn

2052 Chinese PRC zh_pr

32772 Chinese Simplified zh_sm

4100 Chinese Singapore zh_si

1028 Chinese Taiwan zh_ta

31748 Chinese Traditional zh_cht

33796 Chinese Traditional_old zh_tdo

518 Croatian hr

- 276 -
Forsta Confidential Forsta v2022 Scripting Manual

Language code Language Sub-name Combident

5 Czech cs

6 Danish da

19 Dutch nl

2067 Dutch Belgium nl_be

1043 Dutch Netherlands nl_nl

9 English en

3081 English Australia en_au

10249 English Belize en_be

4105 English Canada en_ca

9225 English Caribbean en_ca

6153 English Ireland en_ir

8201 English Jamaica en_ja

5129 English New Zealand en_nz

13321 English Philippines en_ph

33801 English Somali en_so

7177 English South Africa en_sa

32777 English Tagalog en_tg

11273 English Trinidad en_tr

2057 English United Kingdom en_gb

1033 English United States en_us

12297 English Zimbabwe en_zi

37 Estonian et

56 Faeroese fo

41 Farsi fa

- 277 -
Forsta v2022 Scripting Manual Forsta Confidential

Language code Language Sub-name Combident

11 Finnish fi

12 French fr

2060 French Belgium fr_be

3084 French Canada fr_ca

5132 French Luxembourg fr_lu

6156 French Monaco fr_mo

1036 French Standard fr_fr

4108 French Switzerland fr_sw

514 Gaelic gd

55 Georgian ka

7 German de

3079 German Austria de_au

5127 German Liechtenstein de_li

4103 German Luxembourg de_lu

1031 German Standard de_de

2055 German Switzerland de_sw

8 Greek el

513 Greenlandic gl

71 Gujarati gu

13 Hebrew he

57 Hindi hi

14 Hungarian hu

15 Icelandic is

33 Indonesian id

- 278 -
Forsta Confidential Forsta v2022 Scripting Manual

Language code Language Sub-name Combident

32801 Indonesian Bahasa id_ba

1057 Indonesian Indonesia id_id

16 Italian it

1040 Italian Standard it_it

2064 Italian Switzerland it_sw

17 Japanese ja

75 Kannada kn

96 Kashmiri ks

2144 Kashmiri India ks_in

63 Kazak kk

520 Khmer kh

33288 Khmer Cambodian kh_kc

87 Konkani ki

18 Korean ko

2066 Korean Johab ko_jo

1042 Korean Korea ko_ko

38 Latvian lv

39 Lithuanian lt

2087 Lithuanian Classic lt_cl

1063 Lithuanian Lithuania lt_lt

47 Macedonian mk

62 Malay ms

2110 Malay Brunei Darussalam ms_br

1086 Malay Malaysian ms_ms

- 279 -
Forsta v2022 Scripting Manual Forsta Confidential

Language code Language Sub-name Combident

76 Malayalam ml

515 Maltese mlt

88 Manipuri ma

78 Marathi mr

97 Nepali ne

2145 Nepali India ne_in

20 Norwegian no

1044 Norwegian Bokmål no_bo

2068 Norwegian Nynorsk no_ny

72 Oriya or

516 Pashto ps

33284 Pashto Afgan ps_af

34308 Pashto Deewa ps_dw

21 Polish pl

22 Portuguese pt

1046 Portuguese Brazil pt_br

2070 Portuguese Standard pt_st

70 Punjabi pa

24 Romanian ro

25 Russian ru

79 Sanskrit sa

26 Serbian / Croatian sr

1050 Serbian / Croatian Croatian sr_yu

3098 Serbian / Croatian Cyrillic sr_cy

- 280 -
Forsta Confidential Forsta v2022 Scripting Manual

Language code Language Sub-name Combident

2074 Serbian / Croatian Latin sr_la

89 Sindhi sd

519 Sinhalese si

27 Slovak sk

36 Slovenian sl

526 Sotho Sesotho st


60942 Sotho Northern Sotho st-nso

10 Spanish es

11274 Spanish Argentina es_ar

16394 Spanish Bolivia es_bo

13322 Spanish Chile es_ch

9226 Spanish Colombia es_co

5130 Spanish Costa Rica es_cr

7178 Spanish Dominican Republic es_dr

12298 Spanish Ecuador es_eq

17418 Spanish El Salvador es_el

4106 Spanish Guatemala es_gu

18442 Spanish Honduras es_ho

2058 Spanish Mexican es_me

3082 Spanish Modern Sort es_ms

19466 Spanish Nicaragua es_ni

6154 Spanish Panama es_pa

15370 Spanish Paraguay es_pa

10250 Spanish Peru es_pe

20490 Spanish Puerto Rico es_pr

- 281 -
Forsta v2022 Scripting Manual Forsta Confidential

Language code Language Sub-name Combident

1034 Spanish Traditional Sort es_es

14346 Spanish Uruguay es_ur

8202 Spanish Venezuela es_ve

65 Swahili sw

29 Swedish sv

2077 Swedish Finland sv_fi

1053 Swedish Sweden sv_sv

73 Tamil ta

68 Tatar tt

74 Telugu te

30 Thai th

31 Turkish tr

34 Ukrainian uk

32 Urdu ur

2080 Urdu India ur_in

1056 Urdu Pakistan ur_pa

67 Uzbek uz

2115 Uzbek Cyrillic uz_cy

1091 Uzbek Latin uz_la

42 Vietnamese vi

512 Welsh cy

521 Zulu zu

- 282 -
Forsta Confidential Forsta v2022 Scripting Manual

APPENDIX D: Codepage

Arabic ASMO-708 708

Arabic (DOS) 720

Arabic (ISO) 28596

Arabic (Windows) 1256

Baltic (ISO) 28594

Baltic (Windows) 1257

Central European (DOS) 852

Central European (ISO) 28592

Central European (Windows) 1250

Chinese Simplified (GB2312) 936

Chinese Simplified (HZ) 52936

Chinese Traditional 950

Cyrillic (DOS) 866

Cyrillic (ISO) 28595

Cyrillic (KOI8-R) 20866

Cyrillic (Windows) 1251

Greek (ISO) 28597

Greek (Windows) 1253

Hebrew (DOS) 862

Hebrew (ISO) 28598

Hebrew (Windows) 1255

Japanese (JIS) 50220

Japanese (JIS-Allow 1-byte Kana) 50221

Japanese (JIS-Allow 1-byte Kana - 50222


SO/SI)

Japanese (EUC) 51932

- 283 -
Forsta v2022 Scripting Manual Forsta Confidential

Japanese (Shift-JIS) 932

Korean 949

Korean (ISO) 50225

Latin 3 (ISO) 28593

Thai (Windows) 874

Turkish (Windows) 1254

Turkish (ISO) 28599

Ukrainian (KOI8-U) 21866

Unicode (UTF-7) 65000

Unicode (UTF-8) 65001

Vietnamese (Windows) 1258

Western European (Windows) 1252

Western European (ISO) 1252

- 284 -
Forsta Confidential Forsta v2022 Scripting Manual

APPENDIX E: List of Examples


Example

1. Screening Based on a Single Question


2. Filtering a Single Question Based on Answers to a Multi
3. Excluding a Column (Question) in a 3D Grid
4. Piping in the Response to a Single Question
5. Password Check
6. Setting complete status before the end of the survey
7. Displaying a Dynamic Follow-Up Question in the same Page
8. Removing an Answer in a Single or Grid Question
9. Screening on a Numeric Question
10. Response Piping from a Single Question with Other Specify
11. Conditional Code Masking
12. Replacing "NO RESPONSE" in Response Piping
13. Using switch to set Values for each of the Answer Alternatives on a Single
14. Validating Sums in a 3D Grid Using a for Loop
15. Validating Sums in a 3D Grid Using a while Loop
16. Validating Sums in a 3D Grid Using a do while Loop
17. Copying a Multi to do Response Piping with "Other, specify"
18. Validating Sums in a 3D Grid Using a for Loop and break
19. Calculating Averages in a Grid
20. Calculating Averages on a Single Question in a Loop
21. Validating Sum on a Numeric List Question
22. Validating Sums in a 3D Grid with the Sum Function
23. Finding the Number of Answers on Three Multi Questions
24. Calculating Averages on 3 Numeric List Questions in a 3D Grid
25. Finding Maximum and Minimum Values on Numeric Multi Questions
26. Building a Condition on a Range of Codes
27. Displaying different instruction if Advanced WI feature is being used
28. Building a Cryptic URL to be Displayed in an Info Node
29. Calculating the number of days elapsed since a record was uploaded
30. Setting Interview Status Before End of Survey
31. Recording the Respondent's Browser Type and Version
32. Quota Check
33. Presetting a Quota Question to Check Several Quotas
34. Allocate a Respondent to the Lowest Current Quota Cell
35. Displaying Current Credit Balance in a Survey
36. Calculating Credit Balance for the Last 30 Days

- 285 -
Forsta v2022 Scripting Manual Forsta Confidential

37. Retrieving and Listing the last 10 Panelist Credits Transactions inside a Survey
38. Retrieving and Listing the last 10 Panelist Credits Transactions inside a Survey, including custom variables
39. Inserting a new Panelist in a Panel
40. Update Panel Variables in a Panel
41. Retrieving Data for a Panelist in a Panel
42. Update Survey History Panel Variables in a Panel
43. Redirect back to Panel Portal
44. Checking that a Response in a Multi Open Text Question is an Integer
45. Validating Date Format of Open Text Date Question
46. Validating Date with Drop-downs for the Date Parts
47. Validation of Email Address Format
48. Excluding Respondents from Specific Networks
49. Send Confirmation Email at the End of a Survey
50. Invitation Email to a Different Part of the Same Survey
51. Sending a PDF to the respondent with answers from the survey
52. Redirect to Another Site Before the End Page
53. Code Masking Based on a Variable Number of Conditional Expressions
54. Returning a Calculated Value from a Function
55. Using a Variable instead of Repeated Calls on the f Function
56. Deleting the Content of any Question
57. Copying the Contents of any Form into Another
58. Filtering an Answer List by the First Characters in the Answer
59. Asking for Favorite Only when More than 1 Item is Chosen
60. Filtering an Answer List on Items Selected in Two Previous Questions
61. Filtering Answers Not Selected in a Previous Question
62. Always Including a "Don't know" Answer Alternative
63. Validating "Other, specify" in a 3D Grid
64. Using a Function to Filter an Answer List Based on the Answers on a Grid
65. Using a Hidden Multi to Filter an Answer List Based on a Grid
66. Calculating Time Spent
67. Validating that a Date with Drop-downs is within the next two Weeks
68. Finding the Weekday
69. Converting Data of Birth into Age (in number of years)
70. Rounding to a Number with Two Digits
71. Picking n Random Items from the Answers to a Multi Question
72. Randomly Assigning which Part of a Survey the Respondents Should Answer
73. Using modulus to route respondents to different parts of the questionnaire
74. Checking a User Name and Password where Username is Case Insensitive
75. On the Fly Recoding

- 286 -
Forsta Confidential Forsta v2022 Scripting Manual

76. Replacing Last Comma with "and" in a Listing of Answers


77. Generating an Array from a String with Values
78. Validation of the Format of a Phone Number
79. Using Regular Expression to Replace Commas With Line Breaks
80. Post Codes in the United Kingdom
81. Converting an Array to a String with Line Breaks between Elements
82. Validating Grid with "Other, specify" Alternatives
83. Sending in Values with the URL
84. Recording respondent’s browser version and operating system
85. Using Cookies to Limit Access to an Open Survey

- 287 -
Forsta v2022 Scripting Manual Forsta Confidential

APPENDIX F: QSL-to-Forsta Script Conversions


This table provides examples of conversions from the QSL-script used in Pulse Train projects to the script used in
Forsta projects.

Section QSL Forsta Forsta more info. Description

Routing

IF var_single(1);
If f(‘var_single’)==’1’ Use in Condition Check if answer
ENDIF; Node category 1 of
single var is
switched on

IF var_single(1 | 2);
f(‘var_single’)==’1’ || f(‘var_single’)==’2’ Consider nset() and Check if answers
ENDIF; or nnset() when using 1 OR 2 are
set('1','2').inc(f('var_single')) numeric codes switched on

IF ^var_single(1);
!(f(‘var_single’)==’1’ ) or “ Check if single var
does NOT have
code 1 switched
ENDIF; f(‘var_single’)!=’1’
on

IF var_multiple(1); f(‘var_multiple’).inc(‘1’) “ Check if answer 1


switched on in
multiple var
ENDIF;

Consider nset() and


IF var_multiple(1 & 2); f(‘var_multiple’).inc(‘1’) && nnset() when using Check if answers
f(‘var_multiple’).inc(‘2’) numeric codes 1 AND 2 are
or switched on in
ENDIF;
set('1','2').isect(set('1','2')).size() == 2 multiple variable

IF var_single(1) | var_multiple(1); f(‘var_single’)==’1’ || “ Check if answer 1


f(‘var_multiple’).inc(‘1’) is switched on in
EITHER single var
ENDIF;
OR multiple var

IF var_single(1) & var_multiple(1); f(‘var_single’)==’1’ && “ Check if answer 1


f(‘var_multiple’).inc(‘1’) is switched on in
BOTH single var
ENDIF;
and multiple var

If var_multiple(1 || 5); InRange('var_multiple'1,5) Consider nset() and Checks if ANY


or nnset() when using answers between
set('1','2','3','4','5').isect(f('var_multiple')).s numeric codes 1 and 5 are
ENDIF;
ize() > 0 selected (ie 1 or 2
or 3 or 4 or 5)

If var_multiple(1 && 5);

- 288 -
Forsta Confidential Forsta v2022 Scripting Manual

Section QSL Forsta Forsta more info. Description

ENDIF f(‘var_multiple’).inc(‘1’)&& Consider nset() and Checks if ALL


f(‘var_multiple’).inc(‘2’) && nnset() when using answers between
f(‘var_multiple’).inc(‘3’) && numeric codes 1 and 5 are
f(‘var_multiple’).inc(‘4’) && f(‘var_multiple selected (ie 1 and
or 2 and 3 and 4 and
set('1','2','3','4','5').isect(f('var_multiple')).s 5)
ize() == 5

IF var_quantity==1; f(‘var_quantity’).toNumber()==1 “ Check if quantity


variable is equal to
1
ENDIF;

IF var_quantity>>1; f(‘var_quantity’).toNumber() > '1' Remember Check if quantity


.toNumber(), to var is greater than
ensure numeric 1
ENDIF;
evaluation

IF var_quantity>=1; f('var_quantity’).toNumber() >= '1' " Check if quantity


var is greater than
or equal to 1
ENDIF;

IF var_quantity<<1; f('var_quantity’).toNumber() < '1' " Check if quantity


var is less than 1
ENDIF;

IF var_char=='abcde'; f(‘var_char’)==’abcde’ See also String.match Check if character


/ String.replace / variable is equal to
String.search in ‘abcde’
ENDIF;
Scripting manual

Run Mode IF RUN_MODE()==R$4(WEB); GetSurveyChannel == ‘Cawi’ Use in Condition node Checks if Run
(Web) Mode is Web
ENDIF;

Run Mode IF RUN_MODE()==R$4(CATI); GetSurveyChannel == ‘Cati’ “ Checks if Run


(Cati) Mode is Cati
ENDIF;

Run Mode IF RUN_MODE()==R$4(CAPI); GetSurveyChannel == ‘Capi’ “ Checks if Run


(Capi) Mode is Capi
ENDIF;

Case CASE VAR_SINGLE Switch(f(‘var_single’).get() See Switch statement


in Scripting manual
WHEN (1); { Case ‘1’ : <code 1 actions>

COMMENT Actions for when break


var_single is code 1;

WHEN (2); Case ‘2’ : <code 2 actions>

- 289 -
Forsta v2022 Scripting Manual Forsta Confidential

Section QSL Forsta Forsta more info. Description

COMMENT Actions for when break Routing using


var_single is code 2; Case statement;
(an alternative to
“if single_var(1)
WHEN (3); Case ‘3’ : <code 3 actions>
then.....else if
single(var(2)
WHEN (4); Break then.....else if
single_var(3) then
WHEN OTHERS; Case ‘4’ : <code 4 actions> .....else if
single_var(4)
then.....else.....”)
COMMENT Actions for if not break
caught by above cases;

ENDCASE; default: <actions for any other case>

While WHILE (<condition>); While (<condition>) See While in Scripting While loop – stay
manual – also see ‘Do in while loop while
While’ and ‘For’ in condition
ENDWHILE; { <statements> }
Scripting manual evaluates to True

Redo REDO <var_name>; Redirect(GetRespondentUrl()+'&__qid=x Where xx is the qid Ask a question


x',true) you want to start re- again
doing. One should
also use script to 'end'
the redo. Or,
consider using Call
Blocks.

Operators

Arithmetic + + Scripting – Operators Addition

- - Scripting – Operators Minus

/ / Scripting – Operators Division

* * Scripting – Operators Multiplication

Relational == == or === (depending on with/without Scripting – Operators Equals


type conversion)

>> > Scripting – Operators Greater than

>= >= Scripting – Operators Greater than or


equals

=< <= Scripting – Operators Less than or


equals

- 290 -
Forsta Confidential Forsta v2022 Scripting Manual

Section QSL Forsta Forsta more info. Description

<< < Scripting – Operators Less than

<> != or !== (depending on with/without type Scripting – Operators Not equals


conversion)

Logical & && Scripting – Operators And operator

| || Scripting – Operators Or operator

^ ! Scripting – Operators Not operator

Calculations

Temp TEMPORARY <temp_var>; vartemp_var : int; OR vartemp_var : int Defined in script Creates a
= value (if assigning as well) nodes, and validation temporary quantity
code. variable

Increment INCREMENT <var_name>; ++ <var_name> See Arithmetic Increments a


Operators in Scripting variable (either
manual (also useful is quantity or temp
-- to decrement) variable)

Zero ZERO <temp_var_name>; variablename = 0; Assuming variable Sets to zero a


has been previously temporary variable
defined in the
script. If not, use
vartemp_var_name :
int = 0

Compute COMPUTE <target_var> f('target_var').set(f('var1').toNumber() + Using Sum() is a Set value in


(<var1>+<var2>); f('var2').toNumber()) better option, when target_var to be
or dealing with several sum of var1 + var2
f('target_var').set(Sum(f('var1').toNumber previously defined
(),f('var2').toNumber()) variables, or the
values from a multi
question: varmySum
=
Sum(f('var_multiple').v
alues()) will sum up
any number of
answers, given in
var_multiple.

Off OFF var_multiple 1; f(‘var_multiple’)[1].set(null) Switches OFF


answer category 1
in var_multiple

On ON var_single 2; f(‘var_single’).set(‘2’) Switches ON


answer category 2
in var_single

Clear (single) CLEAR var_single; f(‘var_single’).set(null) Set Clears any value


in single variable

- 291 -
Forsta v2022 Scripting Manual Forsta Confidential

Section QSL Forsta Forsta more info. Description

Clear CLEAR var_multiple; f(‘var_multiple’)[<code>].set(null) Set Clears any value


(multiple) in multiple variable
This will need to be iterated for each
code. Or, to clear all codes:
function ClearMulti(MVar)
{
var codes = f(MVar).domainValues();
for(var i : int = 0; i<codes.length ; i++)
{
var code = codes[i];
f(MVar)[code].set(null);
}
}
ClearMulti('var_multiple')

Clear CLEAR var_quantity; f(‘var_quantity’).set(null) Set Clears any value


(quantity) in quantity variable

Clear (char) CLEAR var_char; f(‘var_char’).set(null) Set Clears any value


in character
variable

Masking

<var1> | <var2> f(‘var1’).union(f(‘var2’)) Union Include answers


that are switched
on in EITHER var1
or var2

<var1> & <var2> f(‘var1’).isect(f(‘var2’)) Isect Includes answers


that are switched
on in BOTH var1
and var2

var1 | var2 + TRUE(1) f(‘var1’).union(f(‘var2’)).union(set(‘99’)) Union Include answers


that are switched
on in EITHER var1
or var2, also
always include last
answer (eg Don’t
Know or Refused)

var1 & ^(var2) f(‘var1’).diff(f(‘var2’)) Diff Include answers


switched on in
var1 but exclude
answers switched
on in var2

Quotas

- 292 -
Forsta Confidential Forsta v2022 Scripting Manual

Section QSL Forsta Forsta more info. Description

Define quota <quota_name>: LOOKUP_B These are defined in the Questionnaire Defines quota
<var_single> (150 150); Tree. Refer to the separate Survey <quota_name>
Designer user guide for further where target
information. quotas are 150 in
answer1 and 150
in answer2 from
<var_single>

Check quotas IF ^<quota_name>; qf('quotaname') Use in Condition Checks if target in


Node quota cell has
been reached; if it
ABANDONED QUOTAFAIL ;
has then interview
is abandoned and
ENDIF; status set to
quotafail

Assign quotas Compute <quantity_var> f('quantity_var').set(qc('quota_name')) sets current count into Computes to
to variable Quota_Value(<quota_name>,1) question <quantity_var> the
'quantity_var'. current number of
Achieved
interviews in cell 1
of <quota_name>

Compute <quantity_var> f('quantity_var').set(qt('quota_name')) sets quota target into Computes to


Lookup_Value(<quota_name>,1) question <quantity_var> the
'quantity_var'. Howev current number of
er, we could just use: Target interviews
var x = in cell 1 of
qt('quota_name'), if <quota_name>
working in a script
node.

Functions

Count count(var_multiple)>>1 f(‘var_multiple’).size() Size Count function


returns number of
answers set to
True in variable

Random Random(5) Math.ceil(Math.random()*5) Returns a random


number between 1
and 5

Range Range(var_quantity,0,18,66) var no = f('var_quantity').toNumber(); Computes quantity


var single = f('single_var'); variable into
if(InRange(no,0,17)) single; in this
single.set('1'); example
else if(InRange(no,18,65)) var_quantity is a
single.set('2'); quantity var with
else if(InRange(no,66,99)) range of 0-99 (eg
single.set('3'); age question),
target var is a
single with answer
categories:

- 293 -
Forsta v2022 Scripting Manual Forsta Confidential

Section QSL Forsta Forsta more info. Description

Under 18
18 to 65 inc
66 or more
Appropriate
answer category
will be switched on
in target
depending on
value of
age_quantity

Remainder Remainder(dividend,divisor) Dividend%divisor Modulus Returns remainder


from dividend
divided by divisor;
eg if value of
var_name is 11
then Remainder(v
ar_name,3) would
return 2

Unrecorded Unrecorded(<var_name>) (!f('var_name').toBoolean()) Boolean Returns True if


<var_name> is
unrecorded

Not ^Unrecorded(<var_name>) f(‘var_name’).toBoolean() Boolean Returns True if


Unrecorded <var_name> has a
value

Date
functions

Day Day_of_Month() vardate_var = new Date().getDate() Function that


returns day of
current date (eg
15th Jan would
return 15)

Month Month() varmonth_var = new Returns month of


Date().getMonth()+1; current date (eg if
June, would return
6)

Year Year() varyear_var = new Date().getFullYear(); Returns year of


current date

Misc.

Comments COMMENT this is a comment; // this is a comment Adding a comment


to a script
/* this is a
multiline comment
*/

- 294 -
Forsta Confidential Forsta v2022 Scripting Manual

Section QSL Forsta Forsta more info. Description

DTS (answer <%var_name> ^f(‘var_name’)^ Piping Substitutes


to variable) answer to
var_name (if
var_name is a
categorical
variable then it
substitutes answer
category text)

DTS <(conditional_expression)/TrueTex ^condition ? TrueText :FalseText^ Conditional If condition


(conditional t/FalseText> Expression Ternary evaluates to True
text) Operator then interview
engine inserts
TrueText,
otherwise it inserts
FalseText

DTS <(conditional_expression)%var_na ^condition ? f(‘var_name’) : “”^ Conditional If condition


(conditional me> Expression Ternary evaluates to True
answer to a Operator then insert answer
question) to var_name

DTS (date) %D ^new Date()^ Inserts full datetime Inserts date


value

DTS (tel %T GetTelephoneNumber() Inserts telephone


number) number (only
appropriate for
CATI)

Call Count CALL_COUNT() GetCallAttemptCount() Returns the


number of
telephone calls
that have been
placed to this
record on previous
occasions

- 295 -
Forsta v2022 Scripting Manual Forsta Confidential

Index

?
- (operator), 27 ? (regular expression syntax), 205, 208
-- (operator), 28 ? : (operator), 30
- (regular expression syntax), 206 ?! (regular expression syntax), 210
?: (regular expression syntax), 209
?= (regular expression syntax), 210
!
! (operator), 28 [
!= (operator), 29
!== (operator), 29 [] (regular expression syntax), 205, 206

# \
#, 15, 22, 27, 28, 29, 30, 35, 204, 205, 206, 207, 208, \ (regular expression syntax), 205, 210, 211
209, 210, 211, 256, 257 \\ (regular expression syntax), 205
\- (regular expression syntax), 207
\\ (string formatting character), 22
$ \' (string formatting character), 22
$ (regular expression syntax), 204, 208 \", 22
\$ (regular expression syntax), 205
\( (regular expression syntax), 205
% \) (regular expression syntax), 205
\* (regular expression syntax), 205
% (operator), 27
\. (regular expression syntax), 205
%= (operator), 30
\? (regular expression syntax), 205
\[ (regular expression syntax), 205
& \^ (regular expression syntax), 205
\{ (regular expression syntax), 205
&& (operator), 28 \| (regular expression syntax), 205
\+ (regular expression syntax), 205
( \b (regular expression syntax), 208
\B (regular expression syntax), 208
() (regular expression syntax), 204, 209 \b (string formatting character), 22
(semi colon), 35, 257 \c (regular expression syntax), 206
\d (regular expression syntax), 211
* \D (regular expression syntax), 211
\f (regular expression syntax), 206
* (operator), 27 \n (regular expression syntax), 206
* (regular expression syntax), 204, 208 \n (string formatting character), 22
*= (operator), 30 \r (regular expression syntax), 206
\r (string formatting character), 22
\s (regular expression syntax), 206
. \S (regular expression syntax), 206
. (regular expression syntax), 205 \t (regular expression syntax), 206
.any, .all and .none, 179 \t (string formatting character), 22
\u (regular expression syntax), 211
\v (regular expression syntax), 206
/ \w (regular expression syntax), 211
/ (operator), 27 \W (regular expression syntax), 211
/* */ (comment), 15 \x (regular expression syntax), 211
// (comment), 15
/= (operator), 30 ^
^ (regular expression syntax), 205, 207, 208

- 296 -
Forsta Confidential Forsta v2022 Scripting Manual

{ Answer required checks, 220


Answer Required Checks, 222
{ } (curly brackets), 35, 36, 256 Answer Size For Fixed-Width Fields, 224
{} (regular expression syntax), 205, 208 Answer size tests for fixed-width fields, 220
AnswerOrder, 98
Answers to Exercises, 270
| any, 47
| (regular expression syntax), 205, 209 AppendErrorMessage (function), 9
|| (operator), 28 APPENDIX D, 281
APPENDIX E, 283
AppendQuestionErrorMessage (function), 9
+ Applying the Methods, 48
+ (operator), 27, 29 AppVersion, 100
+ (regular expression syntax), 204, 208 argument, 72, 162
++ (operator), 28 parameter array, 162
+= (operator), 29 arguments Object is not Available, 2
Arithmetic Functions, 72
Arithmetic Operators, 27
< array, 39
declare, 39, 40
< (operator), 29 literal, 39
<= (operator), 29 Array (object), 215
concat (method), 215
= join (method), 216
length (property), 41
= (operator), 29 methods, 215
-= (operator), 29 pop (method), 216
== (operator), 28 push (method), 216
=== (operator), 28 reverse (method), 217
shift (method), 216
> slice (method), 219
sort (method), 2, 217
> (operator), 29 splice (method), 219
>= (operator), 29 toString (method), 216
unshift (method), 216
valueOf (method), 216
3 Arrays, 39
3D Grid, 59 asin (method), 194
3rd Party Integrations, 161 AskMe, 101
AskMe App, 100
AskMe App Specific Functions, 104
A ASP.NET Intrinsic Objects, 228
a (function), 171 assignment (statement), 35
abs (method), 197 Assignment Operators, 29
Accessing Survey Content, 235 atan (method), 194
Accessing the Call Object, 125 atan2 (method), 194
acos (method), 194 Average (function), 76
add (method), 179
Add (method), 232 B
add and remove, 179
addition (operator), 27 Background Audio Capture, 102
AddPanelSurveyHistory, 145 Basic Panels, 145
AddRespondentToCati, 122 BatteryLevel, 100
AddToCatiBlacklist, 120 between, 48
AdvancedWIFeaturesEnabled, 80 big (method), 202
Aggregated Table Script, 247 binary operator, 27
aggregated tables, 235 Blacklist, 120
all, 48 blink (method), 202
anchor (method), 202 block, 35
Anchors, 208 bold (method), 202
and (operator), 28 BOOL (property), 167
and toUTCString, 187 Boolean, 21, 25

- 297 -
Forsta v2022 Scripting Manual Forsta Confidential

false, 21 concat (method), 201, 215


true, 21 conditional expression ternary operator, 30
break (statement), 37, 67 Conditional Expression Ternary Operator, 30
Browser, 265 conditions, 4
Browser Information, 94 const, 16, 35
BrowserType (function), 94 constant, 16
BrowserVersion (function), 94 name, 16
Built-in Functions, 72 scope, 16
byte, 20 constructor, 164
Context Information, 78
continue (statement), 68
C conversion, 22
Caching of Tables, 235 explicit, 22
Call Block, 157 implicit, 23
CancelSurveyNotification, 107 narrowing, 23
CancelSurveyNotifications, 107 widening, 23
CAPI, 101, 259 Conversion Methods in JScript .NET, 23
CAPI and AskMe App, 100 Converting to String from Other Types, 198
CAPI and AskMe App Shared Functions, 100 Cookie, 269
CAPI App Specific Functions, 103 Cookies, 232, 268
CapiAssignRespondent, 104, 128 Cookies (property), 229, 232
CapiUnassignRespondent, 104, 129 Cookies.Get, 269
Capture Order Multis, 95 Cookies.Save, 269
case, 37 cos (method), 193
categories (method), 43 Count (function), 75
categoryLabels (method), 45 CreateCatiAppointment, 122
CATI, 120, 259 CreateCookieObject, 269
CATI Script Code, 125 CreatePanelist (function), 138
CATI Specific Functions, 108 Creating Your Own Functions, 161
CAWI, 259 Credits in Panels, 134
CAWI to CAPI, 128 CSS Interpretation, 91
ceil (method), 194 curly brackets, 35
char, 21 Curly Brackets, 256
charAt (method), 198 CurrentForm, 81
charCodeAt (method), 199 CurrentForm (function), 82
Chart, 129 CurrentID, 84
Chart Script, 248 CurrentID (function), 84
ChartTotal, 129 CurrentLang, 85
Check Script Code, 252 CurrentLang (function), 85
CintFulfillmentRespondentsTransition, 161 CurrentLoops, 85
Classification Functions, 146 CurrentPID, 85
ClearErrorMessage (function), 9 CurrentPID (function), 85
ClearQuestionErrorMessage (function), 9 Custom CATI Script Code, 125
Code masking, 11 Custom Scripting, 125
code masks, 171 Custom variables, 137
Code masks, 5 Custom Variables, 135
CODED (property), 167 Customizing Standard Error Messages, 220
Codelibrary Script, 239
Codepage, 281 D
coercion, 32
Column masking, 11 data declaration, 16
column masks, 7 data type, 16, 19
Columns in 3D grid, 227 array, 39
combident, 10 Array, 215
Combident, 273 Boolean, 21
Combining Set Operators, 176 byte, 20
comments, 15 char, 21
Comments, 256 coercion, 32
Comparison Operators, 28 conversion, 22
Component Scripts, 246 decimal, 21
compound, 165 double, 21
COMPOUND (property), 167 float, 21

- 298 -
Forsta Confidential Forsta v2022 Scripting Manual

int, 20 datestring, 26
long, 20 DateType (object), 232
Number, 21 day, 26
object, 164 day (property), 188
sbyte, 20 decimal, 21
short, 20 decimal numbers, 19
string, 21 declaration (statement), 35
uint, 20 Declare variables, 2
ulong, 20 Declaring JScript Arrays, 40
ushort, 20 Declaring Typed Arrays, 39
Date, 49 decrement (operator), 28
Date (object), 181 DEF_EXCL (error template), 222
Constructors, 181 DEF_EXCL_AND (error template), 223
getDate (method), 185 DEF_EXCL_OR (error template), 223
getDay (method), 184 DEF_NEXCL (error template), 223
getFullYear (method), 183 DEF_NEXCL_AND (error template), 223
getHours (method), 185 DEF_NEXCL_OR (error template), 223
getMilliseconds (method), 186 DeleteCurrentResponse (function), 143
getMinutes (method), 185 device pixel ratio, 91
getMonth (method), 184 DeviceLanguage, 100
getSeconds (method), 186 DeviceLanguageId, 101
getTime (method), 186 DeviceLocale, 101
getTimezoneOffset (method), 187 DeviceModel, 101
getUTCDate (method), 185 DeviceName, 101
getUTCDay (method), 184 DeviceOs, 101
getUTCFullYear (method), 183 DeviceOsVersion, 101
getUTCHours (method), 185 DeviceUniqueId, 101
getUTCMilliseconds (method), 186 DICHOTOMY (property), 167
getUTCMinutes (method), 185 diff (method), 174
getUTCMonth (method), 184 Differences between JavaScript and JScript, 259
getUTCSeconds (method), 186 Digits and Word Characters, 211
getYear (method), 184 division (operator), 27
methods, 182 do while (statement), 65
parse (method), 182 Domain Scripts, 244
setDate (method), 185 domainLabels (method), 43
setFullYear (method), 183 domainValues (method), 43
setHours (method), 185 double, 21
setMilliseconds (method), 186 Dynamic Questions, 11
setMinutes (method), 185 DynamicQuestionsEnabled (function), 80
setMonth (method), 184
setSeconds (method), 186
setTime (method), 186
E
setUTCDate (method), 185 E (property), 193
setUTCFullYear (method), 183 Element of a Grid Question, 58
setUTCHours (method), 185 Element of a Multi Question, 58
setUTCMilliseconds (method), 186 Element of an Open Text List Question, 58
setUTCMinutes (method), 185 else, 36
setUTCMonth (method), 184 EnableLiveMonitoring, 123
setUTCSeconds (method), 186 equal (operator), 28
setYear (method), 184 ErrorTemplate (function), 221
toGMTString (method), 187 DEF_EXCL, 222
toLocaleString (method), 187 DEF_EXCL_AND, 223
toString (method), 187 DEF_EXCL_OR, 223
toUTCString (method), 187 DEF_NEXCL, 223
UTC (method), 182 DEF_NEXCL_AND, 223
valueOf (method), 187 DEF_NEXCL_OR, 223
DATE (property), 167 MAX_SIZE, 224
Date Conversion Methods, 187 MISSING, 222
Date Functions, 187 MISSING_AND, 222
Date Object, 181 MISSING_OR, 222
Date Question Type, 192 NUMERIC_ERRORS, 225
Date Questions, 187 NUMERIC_ERRORS_AND, 225

- 299 -
Forsta v2022 Scripting Manual Forsta Confidential

OTHER, 223 set (method), 42


PRECISION, 225 size (method), 173
PRECISION_ERRORS, 225 text (method), 43
PRECISION_ERRORS_AND, 225 toBoolean (method), 25
RANGE_ERRORS, 226 toDecimal (method), 25
RANGE_ERRORS_AND, 226 toNumber (method), 24
RANGE_MAX, 226 union (method), 173
RANGE_MIN, 226, 227 value (method), 43
RANK_MAX, 224 valueLabel (method), 43
RANK_MIN, 224 values (method), 45
SCALE, 226 false, 21
SCALE_ERRORS, 226 Filter (function), 172
SCALE_ERRORS_AND, 226 Filter Scripts, 250
SEL_EXCL, 222 Filter Summary Script, 245
SEL_EXCL_AND, 222 Filtering Answer Lists, 5
SEL_EXCL_OR, 222 First (function), 96
SEL_NEXCL, 222 fixed (method), 202
SEL_NEXCL_AND, 222 Fixed Number of Arguments, 162
SEL_NEXCL_OR, 222 float, 21
SPEC, 223 floating-point data, 20
TOO_LONG, 224 floor (method), 194
TOO_LONG_AND, 224 fontcolor (method), 202
Exclusivity tests, 220 fontsize (method), 202
Exclusivity Tests, 222 for (statement), 66
ExclusivityError (function), 220, 222 Form (property), 228
exec (method), 212 Form Object, 165
exp (method), 197 form objects, 42
Expires (property), 232 formatting characters (strings), 22
explicit conversion, 22 FormExists, 94
expression, 27 Forward, 88
Expressions, 27 Forward (function), 88
ExprObj, 261 fr, 119
EXTERNAL (property), 167 fromCharCode (method), 199
function, 72
a, 171
F AppendErrorMessage, 9
f (function), 42, 165, 172 AppendQuestionErrorMessage, 9
BOOL (property), 167 argument, 72, 162
categories (method), 43 parameter array, 162
categoryLabels (method), 45 Average, 76
CODED (property), 167 BrowserType, 94
COMPOUND (property), 167 BrowserVersion, 94
compund, 165 call, 72, 162
DATE (property), 167 ClearErrorMessage, 9
DICHOTOMY (property), 167 ClearQuestionErrorMessage, 9
diff (method), 174 Count, 75
domainLabels (method), 43 CreatePanelist, 138
domainValues (method), 43 CurrentForm, 82
EXTERNAL (property), 167 CurrentID, 84
function call, 165 CurrentLang, 85
GEO (property), 167 CurrentPID, 85
get (method), 42 definition, 162
inc (method), 172 DeleteCurrentResponse, 143
instruction (method), 43 DynamicQuestionsEnabled, 80
isect (method), 173 ErrorTemplate, 221
label (method), 42 ExclusivityError, 220, 222
lset (method), 171 f, 42, 165, 172
members (method), 178 Filter, 172
methods, 24, 42, 169, 172 First, 96
NUMERIC (property), 167 Forward, 88
OPEN (property), 167 fr, 119
properties, 167 Get3DGridQuestionIds, 92

- 300 -
Forsta Confidential Forsta v2022 Scripting Manual

GetAvailableSurvey, 159 QuestionErrors, 220


GetCallAttemptCount, 115 RaiseError, 8
GetCapiInterviewerName, 103 RangeError, 221, 226
GetCatiAppointmentTime, 118 RankError, 221, 224
GetCatiInterviewerId, 114 Redirect, 156
GetCatiInterviewerName, 117 Redo, 109
GetCommunityPortalReturnUrl, 142 RequestIP, 95
GetContentType, 79 return (statement), 163
GetDBColumnValue, 98 ScaleError, 221, 226
GetDeviceInfo, 90 SendMail, 151
GetDialingMode, 115 SendMailMultipart, 153
GetDialMode, 115 SendPdfMail, 154
GetDialStatus, 115 SendPdfMailWithCopy, 155
GetExtendedStatus, 113 set, 171
GetExtensionNumber, 110 SetAccessibleMode, 89
GetLastChannelId, 114 SetDialMode, 115
GetLastInterviewStart, 114 SetErrorMessage, 9
GetPanelistCreditBalance, 135 SetExtendedStatus, 113
GetPanelistCredits, 136 SetExtensionNumber, 110
GetPanelVariables, 140 SetInterviewEnd, 86
GetQuestionIds, 92 SetInterviewStart, 86
GetRespondentUrl, 82 SetPanelistCredit, 134
GetRespondentValue, 85 SetQuestionErrorMessage, 9
GetStatus, 87 SetRandomCategories, 88
GetSurveyChannel, 78 SetRespondentValue, 85
GetTelephoneNumber, 109 SetStatus, 88
GetTimeZoneId, 112 SetTelephoneNumber, 109
GetTotalAttempts, 115 SetTimeZoneId, 112
GetTotalDuration, 117 SizeError, 224
InRange, 77 StartVoiceRecording, 119
InRangeExcl, 77 StopVoiceRecording, 119
InterviewEnd, 86, 188 Sum, 72
InterviewStart, 86, 188 TerminateLoop, 88
IsAccessibleMode, 89 trapBrowser, 95
IsDate, 147, 188 UpdatePanelVariables, 139
IsDateFmt, 146, 188 UpdateSurveyHistoryVariables, 141
IsDynamicQuestionCallback, 80 UserParameters, 89
IsEmail, 150 function (Statement), 162
isEmailTaken, 142 Functions Become Constants, 2
isFieldValueTaken, 142 Functions for Sample Only, 143
IsFromCommunityPortal, 142 Functions for Standard Validation, 220
IsInRdgMode, 88 Functions Returning Sets, 171
IsInteger, 146 Functions with a Fixed Number of Arguments, 162
IsNet, 150
IsNumeric, 146
isUsernameTaken, 146
G
Max, 77 Gauge Script, 249
Min, 77 General Utilities, 150
MissingRequiredError, 220, 222 GEO (property), 167
naming conventions, 256 Geolocation Question, 54
nnset, 171 get (method), 42
NotSelectedError, 221, 223 Get3DGridQuestionIds, 92
NotSpecifiedError, 223 GetAdditionalColumnValue, 46
nset, 171 GetAdvertisingInfo, 108
Nth, 97 GetAvailableSurvey
NumericError, 221, 225 function, 159
parseFloat, 23 GetCallAttemptCount, 293
PasswordError, 221 GetCallAttemptCount (function), 115
PrecisionError, 221, 225 GetCapiBatteryLevel, 104
qc, 131 GetCapiDeviceOs, 103
qf, 130 GetCapiInterviewerName
qt, 131 function, 103

- 301 -
Forsta v2022 Scripting Manual Forsta Confidential

GetCatiAppointmentTime GetTimeZoneId (function), 112


function, 118 getTimezoneOffset(method), 187
GetCatiInterviewerId (function), 114 GetTotalAttempts
GetCatiInterviewerName function, 115
function, 117 GetTotalDuration (function), 117
GetCatiInterviews, 124 getType, 46
GetCatiLinkedInterviews, 125 GetUserDeviceVariable, 101
GetCatiRespondentUrl, 119 getUTCDate (method), 185
GetCatiStationId, 119 getUTCDay (method), 184
GetCommunityPortalReturnUrl (function), 142 getUTCFullYear (method), 183
GetCompanyID, 93 getUTCHours (method), 185
GetContentType getUTCMilliseconds (method), 186
function, 79 getUTCMinutes (method), 185
getDate (method), 185 getUTCMonth (method), 184
getDay (method), 184 getUTCSeconds (method), 186
GetDBColumnValue getYear (method), 184
function, 98 greater than (operator), 29
GetDeviceInfo, 90 greater than or equal (operator), 29
GetDeviceUniqueId, 100 Grid Question, 55, 58
GetDialingMode (function), 115
GetDialMode (function), 115
GetDialStatus (function), 115
H
GetDialType, 117 hexadecimal numbers, 19
GetExtendedStatus (function), 113 hidden question, 16
GetExtensionNumber (function), 110 Hide Script, 243, 246
GetExternalSurveyState, 143 Hit List
getFullYear (method), 183 Script, 249
getHours (method), 185 HttpCookie (object)
GetLanguageCodes, 93 Expires (property), 232
GetLastChannelId (function), 114 Name (property), 232
GetLastInterviewStart (function), 114 Path (property), 232
GetLastSurveyNotificationDate, 107 Value (property), 232
GetLeastFilledQuotaCodes, 131 Values (property), 232
getMilliseconds (method), 186 HttpCookie (object):, 232
getMinutes (method), 185 HttpCookiesCollection (object), 232
getMonth (method), 184 Add (method), 232
GetOfflineInfo, 100
GetOfflineSurveyDescription, 104
GetPanelistCreditBalance (function), 135 I
GetPanelistCredits if, 36
function, 136 if (statement), 35
GetPanelistCreditsWithCustomVariables, 137 if-else, 36
GetPanelVariables (function), 140 implicit conversion, 23
GetParamValue, 120 Implicit Conversion of Arrays to Strings, 59
GetQuestionIds, 92 inc, 172
GetRenderingMode, 79 inc (method), 172
GetRespondentUrl, 152 increment (operator), 28
GetRespondentUrl (function), 82 indexOf (method), 199
GetRespondentValue, 85 infinity, 20
GetRespondentValue (function), 85 InRange (function), 77
GetResponseId, 93 InRangeExcl (function), 77
GetRouterName, 160 instruction (method), 43
getSeconds (method), 186 int, 20
GetStatus, 87 integers, 19
GetStatus (function), 87 InterviewEnd, 86
GetSurveyChannel (function), 78 InterviewEnd (function), 86, 188
GetSurveyDeviceVariable, 101 InterviewStart, 86
GetSurveyName, 93 InterviewStart (function), 86, 188
GetSurveyPackageVersion, 93 Introduction, 1
GetTelephoneNumber, 293 IsAccessibleMode, 89
GetTelephoneNumber (function), 109 IsAppNotificationEnabled, 108
getTime(method), 186 IsCallExpired, 120

- 302 -
Forsta Confidential Forsta v2022 Scripting Manual

IsCatiGroupMember, 124 LN10 (property), 193


IsCatiInbound, 124 LN2 (property), 193
IsCatiIvr, 124 log (method), 197
IsDate (function), 147, 188 LOG10E (property), 193
day (property), 188 LOG2E (property), 193
month (property), 189 Logical Operators, 28
year (property), 189 long, 20
IsDateFmt (function), 146, 188 Loop Nodes, 67
day (property), 188 Loop Statements, 62
month (property), 189 loops, 62
year (property), 189 Loops, 58
IsDynamicQuestionCallback (function), 80 lset (method), 171
isect (method), 173
IsEmail (function), 150
isEmailTaken (function), 142
M
Iset, 171 Manual Testing
isFieldValueTaken (function), 142 Professional Authoring, 252
isFinite (method), 24 Mask Script, 245
IsFromCommunityPortal (function), 142 match (method), 213
IsInlineSurveyCallback, 81 Math (object), 193
IsInOpenendReviewMode, 121 abs (method), 197
IsInProductionMode, 79 acos (method), 194
IsInRdgMode, 88 asin (method), 194
IsInRdgMode (function), 88 atan (method), 194
IsInteger (function), 146 atan2 (method), 194
isNaN (method), 24 ceil (method), 194
isNearBy, 48 cos (method), 193
IsNet (function), 150 E (property), 193
IsNumeric (function), 146 exp (method), 197
isUsernameTaken (function), 146 floor (method), 194
italics (method), 202 LN10 (property), 193
LN2 (property), 193
J log (method), 197
LOG10E (property), 193
JavaScript, 259, 260, 261, 262, 264, 265, 266, 268, LOG2E (property), 193
269 max (method), 197
JavaScriptCallResultCollection, 268 methods, 193
JavaScriptScriptingExtensionPoint, 268 min (method), 197
join (method), 216 PI (property), 193
JScript, 259, 260, 261, 262, 265, 266, 268, 269 pow (method), 198
JScript .NET Objects, 181 properties, 193
JScript array, 40 random (method), 195
declare, 40 round (method), 194
sin (method), 193
sqrt (method), 198
L SQRT1_2 (property), 193
label (method), 42 SQRT2 (property), 193
label (statement), 69 tan (method), 194
LangIDs, 10 Math Object, 193
language Math Object Methods, 193
combident, 10 Max (function), 77
Language Code, 273 max (method), 197
lastIndexOf (method), 200 MAX_SIZE (error template), 224
latitude and longitude, 48 Maximum and Minimum, 197
length (property), 41, 198 members, 178
less than (operator), 29 members (method), 178
less than or equal (operator), 29 method, 164
Limitations parseInt, 23
Syntax Highlighter, 14 Methods, 235
link (method), 202 Methods for Setting or Retrieving Values, 183
Linked Surveys / Interviews, 124 Methods for String Objects, 198
List of Examples, 283 Methods of the Form Objects, 42

- 303 -
Forsta v2022 Scripting Manual Forsta Confidential

Min (function), 77 Offline Mobile App Specific Functions, 100


min (method), 197 OPEN (property), 167
MISSING (error template), 222 Open Text List, 53
MISSING_AND (error template), 222 Open Text List Question, 58
MISSING_OR (error template), 222 Open Text Question, 49
MissingRequiredError (function), 220, 222 openAudioinApp, 103
modulus (operator), 27 Opening a Specific Survey Page or Call Block, 157
month, 26 openVideoInApp, 102
month (property), 189 operand, 27
Multi Question, 52, 58 operator, 27
Multimode Functions arithmetic, 27
CAWI to CAPI, 128 addition, 27
multiplication (operator), 27 decrement, 28
division, 27
increment, 28
N modulus, 27
Name (property), 232 multiplication, 27
NameValueCollection, 265 subtraction, 27
NameValueCollection (object), 228, 232 assignment, 29
naming conventions, 256 %= (operator), 30
NaN (not a number), 20, 21, 23, 24 *= (operator), 30
narrowing conversion, 23 /= (operator), 30
negative 0, 20 += (operator), 29
negative infinity, 20 = (operator), 29
NET, 264 -= (operator), 29
new, 30 binary, 27
new (operator), 30, 40, 164 comparision, 28
nnset (function), 171 equal, 28
none, 48 greater than, 29
Non-Printable Characters, 206 greater than or equal, 29
not (operator), 28 less than, 29
not equal (operator), 29 less than or equal, 29
notifyNativeApp, 108 not equal, 29
NotSelectedError (function), 221, 223 strictly equal, 28
NotSpecifiedError (function), 223 strictly no equal, 29
nset (function), 171 conditional expression ternary, 30
Nth (function), 97 logical, 28
null, 17 and, 28
Number, 21 not, 28
NUMERIC (property), 167 or, 28
numeric data, 19 new, 30, 40, 164
Numeric validation, 220 precedence, 33
Numeric Validation, 225 string, 29
NUMERIC_ERRORS (error template), 225 string concatenation, 29
NUMERIC_ERRORS_AND (error template), 225 unary, 27
NumericError (function), 221, 225 Operators and Expressions, 27
or (operator), 28
Order of Precedence, 212
O Ordinary Characters, 204
object, 164 OTHER (error template), 223
Array, 39, 215 Other Specify Items, 56
constructor, 164 Other-specify checking, 220
Date, 181 Other-Specify Checking, 223
form objects, 165 Overview, 60
instance, 164
Math, 193 P
method, 164
property, 164 Page Level Scripts, 241
RegExp, 203 Page Validation Scripts, 242
Set, 171 parameter, 72
String, 198, 213 parameter array, 162
octal numbers, 19 Parameter Scripts, 244

- 304 -
Forsta Confidential Forsta v2022 Scripting Manual

parse (method), 182 methods, 212


parseFloat (function), 23 syntax, 204
parseFloat (method), 24 test (method), 212
parseInt (method), 23, 24 Regular Expression Objects, 213
PasswordError (function), 221 Regular Expression Syntax, 204
Path (property), 232 regular expressions, 203
Permission Scripts, 240 remove (method), 179
PI (property), 193 Removing and Adding Elements, 216
pop (method), 216 Removing Leading/Trailing White Space Characters,
positive 0, 20 203
positive infinity, 20 replace (method), 213
PostponeInterview, 103 Report Level Scripts, 239
pow (method), 198 Reqest.QueryString, 265
PRECISION (error template), 225 Request, 261
PRECISION_ERRORS (error template), 225 Request (object)
PRECISION_ERRORS_AND (error template), 225 Cookies (property), 229, 232
PrecisionError (function), 221, 225 Form (property), 228
Programming Conventions, 256 QueryString (property), 228
Properties, 193, 198 ServerVariables (property), 229
property, 164 Request (object):, 228
push (method), 216 Request.Cookies, 229, 262
Request.Form, 228, 265
Request.ServerVariables, 265
Q RequestForm, 228, 265
qc (function), 131 RequestIP (function), 95
qf (function), 130 Response, 262
qt (function), 131 Response (object), 231
Quantifiers, 207 Write (method), 231
QueryString, 228 response piping, 7, 11
QueryString (property), 228 Response.Write, 254
Question Category, 236 Retrieving the String Value, 202
question id, 16 return (statement), 163
Question masking, 11 reverse (method), 217
QuestionErrors (function), 220 Role Column, 239
Quota, 129 round (method), 194

R S
RaiseError (function), 8 Sample Only, 143
Random, 195 sbyte, 20
random (method), 195 SCALE (error template), 226
Random Data Generator, 253 Scale masking, 11
RANGE_ERRORS (error template), 226 scale masks, 6, 171
RANGE_ERRORS_AND (error template), 226 Scale Masks, 180
RANGE_MAX (error template), 226 SCALE_ERRORS (error template), 226
RANGE_MIN (error template), 226, 227 SCALE_ERRORS_AND (error template), 226
RangeError (function), 221, 226 ScaleError (function), 221, 226
Rank and Capture Order Multis, 95 Scheduling script
Rank order tests, 220 custom script, 125
RANK_MAX (error template), 224 Screen dimension, 91
RANK_MIN (error template), 224 screen.height, 91
RankError (function), 221, 224 screen.width, 91
Redirect, 156 Script .NET Fast Mode, 1
Redirect (function), 156 Script Execution, 12
RedirectToExternalSurvey, 143 script nodes, 10
RedirectToRespondentUrl, 84 Script Types, 239
RedirectToRouterSurvey, 159 Script Validation, 251
Redo (function), 109 Scripting
Referencing the Elements, 57 Guidelines, 235
RegExp (object), 203 Where is it used, 234
Constructors, 203, 212 Scripting Concepts, 235
exec (method), 212 Scripting in Reportal, 234

- 305 -
Forsta v2022 Scripting Manual Forsta Confidential

Scripting Methods, 235 SetAppNotification, 106


Scripts setDate (method), 185
Aggragated Table, 247 SetDialMode (function), 115
Chart, 248 SetErrorMessage (function), 9
Codelibrary, 239 SetExtendedStatus (function), 113
Component, 246 SetExtensionNumber (function), 110
Domain, 244 setFullYear (method), 183
Filter, 250 setHours (method), 185
Filter Summary, 245 SetInterviewEnd, 86
Gauge, 249 SetInterviewEnd (function), 86
Hide, 246 SetInterviewStart, 86
Hit List, 249 SetInterviewStart (function), 86
Mask, 245 setMilliseconds (method), 186
Page Level, 241 setMinutes (method), 185
Page Validation, 242 setMonth (method), 184
Parameters, 244 SetNextCatiInterview, 125
Permissions, 240 SetNextCatiInterviewToPrevious, 125
Report Level, 239 SetOfflineSurveyDescription, 104
Text, 250 SetPanelistCredit, 135
Verbatim Table, 248 SetPanelistCredit (function), 134
search (method), 213 SetPanelistCreditWithCustomVariables, 135
Searching for a Substring, 199 SetQuestionErrorMessage (function), 9
SEL_EXCL (error template), 222 SetRandomCategories, 88
SEL_EXCL_AND (error template), 222 SetRepeatingSurveyNotification, 107
SEL_EXCL_OR (error template), 222 SetRespondentValue, 85
SEL_NEXCL (error template), 222 SetRespondentValue (function), 85
SEL_NEXCL_AND (error template), 222 setSeconds (method), 186
SEL_NEXCL_OR (error template), 222 SetStatus, 87
Semi Colon, 257 SetStatus (function), 88
SendMail (function), 151 SetSurveyDeviceVariable, 101
SendMailMultipart (function), 153 SetSurveyNotification, 106
SendPdfMail, 154 SetTelephoneNumber (function), 109
SendPdfMail (function), 154 setTime(method), 186
SendPdfMailWithCopy, 155 SetTimeZoneId (function), 112
SendPdfMailWithCopy (function), 155 Setting Variables for Nth Mentioned, 98
Server, 264 SetUserDeviceVariable, 101
ServerVariables, 229 setUTCDate (method), 185
ServerVariables (property), 229 setUTCFullYear (method), 183
set, 18 setUTCHours (method), 185
Set, 261 setUTCMilliseconds (method), 186
set (function), 171 setUTCMinutes (method), 185
set (method), 24, 42 setUTCMonth (method), 184
Set (object), 171 setUTCSeconds (method), 186
a (function), 171 setYear (method), 184
add (method), 179 shift (method), 216
Constructor, 171 short, 20
diff (method), 174 short circuit evaluation, 34
Filter (function), 172 ShowAppNotificationSettingsDialog, 108
inc (method), 172 Simple Statements, 35
isect (method), 173 sin (method), 193
lset (method), 171 Single Question, 50
members (method), 178 Single Question with Boolean, 51
methods, 172 size (method), 173
nnset (function), 171 SizeError (function), 224
nset (function), 171 slice (method), 200, 219
remove (method), 179 slice and splice, 219
set (function), 171 small (method), 203
size (method), 173 Some Useful JScript .NET Objects, 181
union (method), 173 sort (method), 2, 217
Set Operators, 176 Spaces and Line Breaks, 256
Set Panelist Credit, 135 SPEC (error template), 223
SetAccessibleMode, 89 Special Characters, 204

- 306 -
Forsta Confidential Forsta v2022 Scripting Manual

splice (method), 219 search (method), 213


split (method), 201 slice (method), 200
Splitting and Joining Strings, 201 small (method), 203
sqrt (method), 198 split (method), 201
SQRT1_2 (property), 193 strike (method), 203
SQRT2 (property), 193 sub (method), 203
Standard and Professional Panels, 138 substr (method), 200
Standard Code, 260 substring (method), 201
startAudioCapture, 102 sup (method), 203
StartCATIAudioPlayback, 121 toLowerCase (method), 199
StartScreenRecording, 123 toString (method), 202
StartVoiceRecording, 119 toUpperCase (method), 199
statement, 35 valueOf (method), 202
assignment, 35 string concatenation (operator), 29
break, 37, 67 String Object Methods, 213
continue, 68 String Operators, 29
declaration, 35 sub (method), 203
declare array, 39, 40 substr (method), 200
do while, 65 substring (method), 201
for, 66 subtraction (operator), 27
function, 162 Sum (function), 72
function call, 72, 162 sup (method), 203
if, 35 Survey Content, 235
label, 69 Survey Reminders, 105, 106, 107, 108
loops, 62 Survey Router Functions, 158
object instantiation, 164 switch (statement), 37
return, 163 Syntax, 259
switch, 37 syntax highlighter, 234
while, 62 Syntax Highlighter, 12
Static Methods, 182 Limitations, 14
Step by Step Approach, 257 Using, 13
stopAudioCapture, 102
StopVoiceRecording, 119
Storing the Form Object in a Variable, 165
T
strictly equal (operator), 28 Table Lookup Specific Functions, 98
strictly not equal (operator), 29 tan (method), 194
strike (method), 203 Telephone Blacklist, 120
string, 21 Template Based Error Messages, 221
formatting characters, 22 TerminateLoop, 88
String (object), 198, 213 Terminology, 27
anchor (method), 202 Ternary Operator, 30
big (method), 202 test (method), 212
blink (method), 202 Testing
bold (method), 202 in Professional Authoring, 252
charAt (method), 198 in Survey Designer, 254
charCodeAt (method), 199 Testing Survey Scripts, 252
concat (method), 201 text (method), 43
constructors, 198 Text Script, 250
fixed (method), 202 text substitution, 7
fontcolor (method), 202 Text substitution, 11
fontsize (method), 202 The Array Object, 215
fromCharCode (method), 199 Tips for Debugging, 254
index, 198 toBoolean, 18, 25
indexOf (method), 199 toBoolean (method), 25
italics (method), 202 toDate, 26
lastIndexOf (method), 200 toDecimal (method), 25
length (property), 198 toGMTString (method), 187
link (method), 202 toLocaleString, 187
match (method), 213 toLocaleString (method), 187
methods, 198, 213 toLowerCase (method), 199
properties, 198 toNumber (method), 24
replace (method), 213 TOO_LONG (error template), 224

- 307 -
Forsta v2022 Scripting Manual Forsta Confidential

TOO_LONG_AND (error template), 224 V


toString, 187
toString (method), 24, 187, 202, 216 Validation, 251
toUpperCase (method), 199 validation code, 8, 220
toUTCString (method), 187 value (method), 43
trapBrowser (function), 95 Value (property), 232
true, 21 valueLabel (method), 43
typed array, 39 valueOf, 187
declare, 39 valueOf (method), 24, 187, 202, 216
Types, Variables and Constants, 16 values (method), 45
Values (property), 232
var, 16, 35
U variable, 16
uint, 20 name, 16
ulong, 20 naming conventions, 256
unary operator, 27 scope, 16
undefined, 17 Variables
Unicode, 22 Declare, 2
union (method), 173 Verbatim Table Script, 248
unshift (method), 216
UpdatePanelVariables (function), 139 W
UpdateSurveyHistoryPanelVariables, 141
UpdateSurveyHistoryVariables (function), 141 Where is Scripting Used, 4, 234
Useful ASP.NET Intrinsic Objects, 228 while (statement), 62
Usercode API, 260 widening conversion, 23
User-Defined Functions in Code, 180 window.innerHeight, 91
UserParameters, 89, 265 window.innerWidth, 91
ushort, 20 Write, 231
Using Curly Brackets in if Statements, 36 Write (method), 231
Using Custom Variables, 135 Writing Custom CATI Script Code, 125
Using the Syntax Highlighter, 13 Writing Efficient Code, 258
UTC, 182
UTC (method), 182
UTC (Universal Coordinated Time), 181
Y
year, 26
year (property), 189

- 308 -

You might also like