SurveyJS Library Overview
This article describes how SurveyJS Library works, its concepts and main functionality.
We recommend that you use the SurveyJS Creator to create a survey without any coding.
For information about integrating a survey into a web page, refer to the Add Survey into your Web Page article.
Please visit our what's new page to see what we have added recently or what is coming soon.
- Supported Platforms
- Survey Objects
- Store Survey Results
- Survey States (From 'running' to 'completed')
- Survey Data, Modify or View Survey Results
- Pages, Visibility and Navigation
- Questions and Containers Conditional Visibility, Read-Only and Required Questions
- Dynamically Filter Choices, Columns, and Rows
- Fill the Choices From a Restful Service
- Readonly and EnableIf Expression
- Text Processing, Dynamic Titles, and HTML Properties
- Calculated Values
- Client and Server-Side Validation
- Localization and Multilanguage Support
- Extend SurveyJS Elements by Adding Properties
- Triggers: Control the Survey Logic
Supported Platforms
The SurveyJS Library is a JavaScript library that available for five platforms:
- Angular
- jQuery
- knockout
- react
- vue
Please note: If you do not use any of this framework and do not use jQuery, then the right choice is knockout. It is a small library that helps creating UI with Model-View-View-Model pattern. You can include knockout script (~25k min+gz) just for SurveyJS and forget about this library existing in your application.
The library itself consists of two parts:
Survey Model
A platform independent part. In the most case, you work with Survey Model.
The platform specific code
This part deals with rendering and processing mouse and keyboard events.
w The jQuery and Angular versions are the wrappers around the knockout version with built-in knockout library in them. Knockout, react, and vue implementations are native.
Survey Objects
SurveyJS implements three main object types:
- survey,
- containers (pages and panels),
- questions.
The survey object is the root element, that contains top level properties/options, methods, and events. It contains top-level containers – pages. Every page may contain unlimited number of panels and questions, where panel can contain another panels and questions (nested panels are supported).
Create Simple Survey Model (Using JSON or in Code)
You can create a survey model in two ways:
- define a survey model in JSON and pass a JSON object to the Survey's constructor as a parameter
- create a survey model in code.
In JSON
The example below demonstrates how to create a simple survey model using JSON. This survey contains a single page and a text question in it:
var json = {
pages: [
{
name: "page1",
elements: [
{ type: "text", name: "question1" }
]
}
]
}
var survey = new Survey.Survey(json);
In the example above, the survey model contains a single page. In this case, you can remove the "pages" and "page1" definition: SurveyJS creates a page automatically. As result, the JSON may look like follows:
var json = {
elements: [
{ type: "text", name: "question1" }
]
}
var survey = new Survey.Survey(json);
In Code
You can create a survey in code:
var survey = new Survey.Survey();
var page = survey.addNewPage("page1");
page.addNewQuestion("text", "question1");
In JSON and in Code
You can combine these two approaches.
The example below demonstrates how to create a survey model in JSON and then modify the model in code.
var json = {
pages: [
{
name: "customerContact", elements: [
{ type: "text", name: "name", title: "Please enter your name:" },
{ type: "text", name: "email", title: "Please enter your e-mail:" }
]
}
]
};
// Create initial survey model using json
var survey = new Survey.Survey(json);
// Create a placeholder for an "email" question
var emailQuestion = survey.getQuestionByName("email");
if (emailQuestion) emailQuestion.placeHolder = "json.snow@nightwatch.org";
// Add a new question into an existing page
var contactPage = survey.getPageByName("customerContact");
if (contactPage) {
var fbPageQuestion = contactPage.addNewQuestion("text", "fbPage");
fbPageQuestion.title = "Please enter your facebook page:"
}
//You may create a new page or remove/add pages, add/remove questions, panels, modify them, etc.
Load Survey From SurveyJS Service
SurveyJS allows you to load a survey model JSON from SurveyJS Service. The main benefit of this approach – you can modify the survey without modifying your web page.
To load survey model from SurveyJS Service, do the following:
Register on SurveyJS web site.
Create a new Survey in the SurveyJS Service.
In the SurveyJS Service page, copy your Survey Id.
Create a survey as shown in a code sample below.
var json = { surveyId: '5af48e08-a0a5-44a5-83f4-1c90e8e98de1' }; var survey = new Survey.Survey(json);
Example
Store Survey Results
After you have created your survey and integrated it into your web site, you need to save the survey results.
You may store survey results:
Use SurveyJS Service Backend
SurveyJS has the backend SurveyJS Service to store your surveys' results. This approach doesn't require to write any code and is free for now.
To store survey results on SurveyJS backend, do the following:
Register on SurveyJS web site.
Create a new survey. If you do not want to load the survey from SurveyJS service, then you do not need to keep the survey definition in the service.
Get a Post Id for a new survey:
Set the Survey's surveyPostId to the PostId value:
var survey = new Survey.Survey(json); survey.surveyPostId = "YourPostIdGuid"; //Optionally, show saving progress and show an error and "Save Again" button if the results can't be stored. survey.surveyShowDataSaving = true;
Example
Show Progress and Try Again Button
You can optionally show the saving progress by setting the surveyShowDataSaving property to true
. When the option is enabled, the survey shows the "Saving..." message. Then, the survey shows if the operation was successful or an error occurred after the callback from SurveyJS service.
If an error occurs, the survey displays the "Save Again" button, so an end user can try to send survey results again.
You can override the default UI and message texts as shown in the code sample below.
Survey.surveyStrings.savingData = "Please wait. We are validating and saving your response.";
Survey.surveyStrings.savingDataError = "That is my own text on error.";
Survey.surveyStrings.savingDataSuccess = "That is my own text on success.";
Survey.surveyStrings.saveAgainButton = "Try to save again.";
Refer to Localization and Multilanguages support section for more information on SurveyJS strings and localization
Store Survey Results in Your Own Database
To store the survey results in your own storage, you use the onComplete event. It fires when an end user clicks the "Complete" button and a survey completion page is displayed.
The implementation of the storing survey results in the database fully depends on your server backend and database.
The code sample below demonstrates how to send the survey results to your service, in case you have implemented the services on your web site:
survey.onComplete.add(function (sender, options) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "YourServiceForStoringSurveyResultsAsJSON_URL");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.send(JSON.stringify(sender.data));
});
Show Progress and Try Again Button
You can show the progress and error messages:
survey.onComplete.add(function (sender, options) {
//Show message about "Saving..." the results
options.showDataSaving();//you may pass a text parameter to show your own text
var xhr = new XMLHttpRequest();
xhr.open("POST", "YourServiceForStoringSurveyResultsURL");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.onload = xhr.onerror = function () {
if (xhr.status == 200) {
options.showDataSavingSuccess(); // you may pass a text parameter to show your own text
// Or you may clear all messages:
// options.showDataSavingClear();
} else {
//Error
options.showDataSavingError(); // you may pass a text parameter to show your own text
}
};
xhr.send(JSON.stringify(sender.data));
});
Modify Survey Results
SurveyJS sends survey results in the following format:
{questionName: questionValue, ... }
The code sample below demonstrates how to change the standard format to
{ questionName:
{
value: questionValue,
title: questionTitle,
displayValue: questionDisplayValue,
tag: question.tag
}
}
... where tag
is a custom property added into question class.
// Adding custom numeric property to a question
// Survey.Serializer.addProperty("question", "tag:number")
function modifySurveyResults(survey) {
var resultData = [];
for(var key in survey.data) {
var question = survey.getQuestionByValueName(key);
if(!!question) {
var item = {value: question.value};
//If question name (question.valueName) doesn't equal to question.title
if(key !== question.title) {
item.title = question.title;
}
//If question value different from displayValue
if(item.value != question.displayValue) {
item.displayValue = question.displayValue
}
//If the custom property tag is defined set
if(question.tag !== undefined) {
item.tag = question.tag;
}
resultData.push(item);
}
}
return resultData;
}
Another option is to use the survey.getPlainData() function. It returns survey result data as an array of plain objects: with question title, name, value, and displayValue.
You may use modifySurveyResults function as modifySurveyResults(survey) instead of survey.data in survey.onComplete event.
Survey States (From 'running' to 'completed')
Survey may have five different states. To get the current state, check the state read-only property. This section describes all the survey states.
State 'empty'
If the survey model has no visible questions/pages, the survey is in the empty state. The widget shows a message that a survey is empty: "There is no visible page or question in the survey.". You can change this text like follows:
Survey.surveyStrings.emptySurvey = "The current survey is empty";
State 'loading'
If the SurveyJS loads a survey model from SurveyJS Service, the survey is in the loading state. The message about survey loading is showing. The widget shows a message that a survey is loading. You can change this text like follows:
Survey.surveyStrings.loadingSurvey = "Please wait. Your survey is loading…";
State 'starting'
SurveyJS can display a start page (with any introduction info about the survey, start button, etc.) before displaying the first survey page. Displaying a start page is necessary when you create a quiz (a limited to time survey).
Set the firstPageIsStarted property to true
to show a start page instead a first survey page when a survey is loaded. An end user cannot come back to a start page after clicking the "start" button.
If the SurveyJS shows a start page, the survey is in the starting state.
You can change the startSurveyText property value to modify the "start" button text.
State 'running'
While survey pages (with "Previous", "Next" and "Complete" buttons) are displayed to an end user, the survey is in the running state.
State 'preview'
You can allow respondents to preview and correct their answers before completing a survey. When survey preview mode is available, a survey's last page displays the "Preview" button instead of the "Complete" button. A respondent's click on the "Preview" button switches the survey to preview state. In preview, all questions (or, optionally, only answered ones) are displayed on one page in read-only mode. Each survey page converts into a panel, every panel contains an "Edit" button". Respondents can then switch to edit mode: for a panel - by clicking the panel's "Edit" button to edit questions of the corresponding survey page, for the entire survey (starting from its beginning) - by clicking the "Edit" button on Navigation tab.
If a respondent is satisfied with the answers, he/she can click the "Complete" button to submit the survey results.
Use the showPreviewBeforeComplete option to control the preview mode's availability and settings. The functionality is disabled by default.
survey.showPreviewBeforeComplete: string, ["noPreview", "showAllQuestions", "showAnsweredQuestions"]
, "noPreview" is the default value.
noPreview
- Preview mode is not available.
showAllQuestions
- Displays all visible questions on the preview page.
showAnsweredQuestions
- Displays only answered visible questions on the preview page. If you change this property when a survey is in the "preview" state and the preview page is displayed, then this change will not take effect.
survey.showPreviewBeforeComplete = 'showAnsweredQuestions';
Example:
Show Preview Before Complete
To dynamically enter/leave preview mode via code, use the showPreview and cancelPreview methods.
survey.showPreview(): boolean
- Switches a survey to the preview state; returns false if there is an error on the page.
survey.cancelPreview()
- Switches back to edit mode.
State 'completed'
When a survey is completed:
- the survey is in the completed state;
- the survey displays a complete page;
- the survey.onCompleted event is fired.
Complete Page
You can turn off the complete page by setting the showCompletedPage to false
. When the complete page is disabled, the survey is still in the completed state, but the survey widget becomes invisible to end users.
Use the completedHtml property to specify the complete page's HTML. This property supports text preprocessing. To see how it works in action, refer to the Process Text example.
Replay Survey in Read-Only Mode
When the survey is completed, the onComplete event occurs. In most cases, this event is used to save the survey results in your own database.
However, you can show the same survey to an end user from the beginning, but in read-only mode:
survey.onComplete.add(function (sender, options) {
// By default, the 'clear' method clears all data and go to the first page
// Make a survey to keep the results by passing the first parameter as 'false'
sender.clear(false);
// Turn a survey into read-only mode
sender.mode = "display";
});
Survey Data, Modify or View Survey Results
SurveyJS provides access to survey results. This can be helpful in the following cases:
- make predefined answers to particular questions before the survey starts
- review survey results
- restore the answered questions if an end user leaves a survey uncompleted
- clear data for invisible questions
- depending on question's answer, modify other question answers.
Survey Data API
Survey expose the surveymodel.data property, that contains survey results in JSON format question name: questions value
.
Every question, except html question that does not have input, has a writable question.value property. The value property does not store its value. The actual question value is stored in survey.data. You can access a question value using the survey.getValue(name) and survey.setValue(name, newValue) functions.
Thus, the myQuestion.value
code returns the same result as survey.getValue(myQuestion.name)
.
To be more precise, the question.name is used, unless question.valueName property is empty. We will talk about valueName property later, in one of described scenarios.
Predefined Answers
You may need to have predefined answers. For example, you need to have a default value for Boolean question as True
. To specify a default value, use the question.defaultValue property. You can specify this property in JSON, or in our Survey Creator. After loading the JSON, on starting the survey, the defaultValue property is copied to the question.value property.
Tip
You can use the question.value property or survey.setValue(name, newValue) function to set the needed value in code at any time.
Review Survey Results
To review survey results, stored in your own data base, you can use a survey in read-only mode:
survey.data = JSON.parse(YourResultAsStringFromDatabase);
survey.mode = "display"; //set a survey to read-only mode
Restore Answered Questions for In-Completed Survey
When an end user does not complete a survey in a single session, and returns to a survey later, you can refill the survey results and a last visited page. You can save the incomplete results in your data base or in a browser local storage.
To save the incomplete results, set the survey.sendResultOnPageNext property to true
. Each time an end user navigates the next page, the survey.onPartialSend event occurs.
The code sample below implements restoring answered questions and current page from a local browser storage.
survey.sendResultOnPageNext = true;
var storageName = "yourSurveyUniqueNameOrId";
function saveSurveyData(survey) {
var data = survey.data;
data.pageNo = survey.currentPageNo;
window.localStorage.setItem(storageName, JSON.stringify(data));
}
survey.onPartialSend.add(function (survey) {
saveSurveyData(survey);
});
survey.onComplete.add(function (survey, options) {
saveSurveyData(survey);
});
var prevData = window.localStorage.getItem(storageName) || null;
if (prevData) {
var data = JSON.parse(prevData);
survey.data = data;
if (data.pageNo) {
survey.currentPageNo = data.pageNo;
}
}
Example
Clear Data for Invisible Questions
SurveyJS clears values for invisible questions by default. To change this behavior, change the clearInvisibleValues property value to:
- none - survey includes the invisible values into the survey data.
- onHidden - survey clears the question value when the question becomes invisible. If a question has an answer value and it was invisible initially, a survey clears the value on completing. This option is useful if you have a cascade condition in
visibleIf
expressions. - onComplete (default) - survey removes property values of invisible questions on survey complete. In this case, the invisible questions will not be stored on the server.
Using Variables
SurveyJS allows you to use variables:
- you can use variables in expressions and text processing,
- variables are not used in questions and are not stored in survey data.
To create a new value or change its value, call survey.setVariable("variableName", value)
. Call survey.getVariable("variableName")
to get the variable value.
On question.value Changed, Modify Other Questions or Change Their Values
In survey scenarios, changing a question value may require changing other questions.
Example 1. In the first question, you ask end users to select producers of cars they drove before. In the second question, you ask end users to select a car producer they like the most, from the car producers selected in the previous question.
Example 2. The first question is "Please select the language(s) you are speaking" and the second question "Please select the language(s) you want to learn". The choices from the second question do not contain selected choices from the first question.
Use the survey.onValueChanged event to implement this scenarios.
The code sample below implements the Example 2.
survey.onValueChanged.add(function(survey, options){
if(options.name !== "know") return;
knownChoices = options.question.choices;
var choices = [];
for(var i = 0; i < knownChoices.length; i ++) {
var item = knownChoices[i];
// the item is not selected
if(options.value.indexOf(item.value) < 0) {
choices.push(item);
}
}
var learnQuestion = survey.getQuestionByName("learn");
learnQuestion.choices = choices;
learnQuestion.visible = choices.length > 0;
});
Refer to the Plunker snippet for the complete code sample.
Note:
The second scenario can be implemented without coding, by setting choicesVisibleIf property. Refer to the Dynamically Filter Choices, Columns and Rows section for more information.
Share the Same Data Between Two or More Questions
SurveyJS allows you to share data between different questions.
This may be useful in the following cases:
- Show the same question on different pages (for example, an end user enters their email on the first page, then confirms it on the last page).
- Create a complex form without additional coding (for example, an end user enters several items, moves to the next page and enters more details for each item).
Having the same question.name is not a good idea, those questions may be different and can have their own logic on showing/hiding or enabling/disabling. For this purpose, we have introduced question.valueName property. If this property is set, then question is using valueName property, instead of name property, to get/set its value from the survey data storage.
You can create complex forms without writing a single line of code. For example, you need to get an information about your user employees. On the first page, the user enters employee names, on the next page(s) the user enters additional information about each of them.
On the first page, you have a matrix dynamic question, with ability to add/delete rows and one column: Name. On the second page, you ask an additional information about employees using panel dynamic. It works fine, because for both questions the value is an array of objects.
Example
Sharing data between matrix dynamic and panel dynamic questions
Pages, Visibility and Navigation
Questions and panels (container) are located on pages. Every survey should have at least one visible page.
Page Visibility
The page is visible if:
- the visible property equals to
true
(the default value), - the visibleIf property is empty (for more information about visibleIf expression, refer to the Conditions section),
- its expression returns
true
and the page has at least one visible question.
SurveyJS doesn't show pages that have no visible questions, it skips them automatically.
Navigation
Page List
Use the following properties to get the survey pages:
- survey.pages - returns a list of all pages;
- survey.visiblePages - returns a list of visible pages. End users navigate visible pages and this array may be changed while a user runs a survey.
Current Page
Use the survey.currentPage property to get or set the current page. If a survey has no visible pages, this property returns null
.
To change the current page from the code you may call:
survey.currentPage = myPage;
// or change the current page using visible page zero-based index
survey.currentPage = visiblePageIndex;
// or change the current page by setting the page name
survey.currentPage = "myCurrentPage";
Navigate Next, Previous Page, or Complete
SurveyJS allows you to navigate survey pages in code:
- to a previous page - call survey.prevPage();
- to a next page - call survey.nextPage();
- to complete a survey - call survey.completeLastPage().
The prevPage() function returns false
and do not change a current page, if the current page is already the first page.
The nextPage() and completeLastPage() functions return false
and do not go to the next page or complete a survey if there are any errors on the current page. An end user must fix them first to go further. Refer to Validation for more information.
SurveyJS exposes the following navigation events:
Set survey.showNavigationButtons to false
to hide the default navigation buttons, and create your own navigation by using these functions and events.
Example
Here are additional properties that you may find useful:
- showPrevButton - set it to
false
to hide the previous button. In this case, your users cannot comeback to the previous page - pagePrevText - specifies the previous button text
- pageNextText - specifies the next button text
- completeText - specifies the complete button text
Automatic Navigation
You can enable the automatic navigation by setting the goNextPageAutomatic property to true
. In this case, a survey automatically goes to the next page when a user has answered all questions.
Example
Survey Progress
To show a progress bar, set the showProgressBar property to top
, bottom
or both
. To change the default text: Page x of N
, change the localization string Survey.defaultStrings.progressText, the default string for English localization is: "Page {0} of {1}".
All Questions on a Single Page
SurveyJS can display all the questions on a single page. It may be useful when you want your users to review their answers in read-only mode. Set the survey.isSinglePage property to true
to display all the questions on a single page.
Skip Pages
SurveyJS allows you to set a visibility expression for individual pages, panels, and questions. If a page has no visible panels or questions, the page becomes invisible. SurveyJS automatically skips invisible pages. Refer to the next section for more information about visibility expressions.
Questions and Containers Conditional Visibility, Read-Only and Required Questions
SurveyJS allows you to implement custom logic in surveys. For example, you may need to ask different questions based on age, for loyal or unhappy customers, or you may make some questions read-only or required based on answers in other questions.
SurveyJS has a powerful and flexible expression engine powered by PEG.js parser generator.
Boolean Expressions
Questions, panels and pages have visibleIf, enableIf and requiredIf properties.
These properties are empty by default. Each element's behavior depends on the isVisible, isReadOnly and isRequired properties. The question containers (panel and page) become invisible if they have no visible questions.
Before rendering the first page, SurveyJS parses all Boolean expressions (visibleIf, enableIf, and requiredIf), creates the expression trees, and run all expressions. Later, SurveyJS runs all expressions after any value change. If the expression returns false
, the element becomes invisible (or read-only or non required), if it returns true
– visible (enabled, required). The question values should be in braces: {yourQuestionValueName}
.
Here are some examples of Boolean expressions.
Expression | Description |
---|---|
" >= 21" | Returns true if the age question has value 21 or higher |
"( + + ) > 21 and == ‘yes’" | Use or and and operators, squares and arithmetic operations |
"!( == ‘yes’ and ( + + ) > 21)" | Use "!" or "not" to change the result on opposite |
" notempty" | Returns true if name has a value |
empty | Returns true if name has no value |
" = [‘English’, ‘Spanish’]" | Returns true , if a user selects these two valus in speakinglanguages question. It is typically a checkbox. |
" contains ‘Spanish’" | Returns true , if a user select 'Spanish' in checkbox. They may or may not select other values. |
age() >= 21 | Returns true , if function age returns 21 and greater. The function age calculates the age based on the birth date and the current date. |
If your question has complex values, then you may use dot "." to access the child value.
- multiple text -
- matrix -
- matrix dropdown -
To access the question value inside the panel dynamic, use the following syntax: {dynamicpanelname[index].questionname}
, where index is zero-based.
To access the cell value of the matrix dynamic, write the following code: {matrix[index].columnname}
, where index is zero-based.
Cell Visibility in Matrix and Dynamic Panel Questions
You can make a cell in a matrix question invisible or disabled based on other cells value on the same row. In this case, use the prefix row
to access a cell value on the same row: {row.columnname}
.
You can use the same approach in dynamic panels. To access questions value on the same panel in the expression, use the panel
prefix: {panel.questionName}
.
Use Functions in Expressions
You can use functions in expressions to perform additional calculations. Functions support an arbitrary number of parameters and share the following general syntax:
functionName(arg1, arg2, ...argN)
The following rules apply:
- functionName
A valid function name in lower camel case. - ()
The function name is followed by an open and close parentheses, even if the function takes no arguments. - ,
The comma is the only allowed delimiter to separate the function arguments. Arguments may be optional.
An expression can contain more than one function calls, including calls to built-in functions and custom functions that you can create.
A function parameter can accept a question value pointer variable - a specific expression that points to a question whose value to obtain and use as a function argument. Such an expression specifies the question by its name in curly brackets, for instance as {question1}
.
As an example, the following expression uses two built-in functions (age
and iif
) to find out whether the value of the "birthdate" question is greater than or equal to 21 and to return "yes"
or "no"
correspondingly.
"expression": "iif(age({birthdate}) >= 21, 'yes', 'no')"
For illustrative purposes, the code sample below shows how the built-in age
function is implemented in SurveyJS sources (see source code for more details).
// The age function accepts the birth date
// and returns the current age as the number of full years.
function age(params: any[]): any {
if (!params && params.length < 1) return null;
if (!params[0]) return null;
var birthDate = new Date(params[0]);
var today = new Date();
var age = today.getFullYear() - birthDate.getFullYear();
var m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age -= age > 0 ? 1 : 0;
}
return age;
}
// The function is registered for use in SurveyJS expressions.
FunctionFactory.Instance.register("age", age);
Built-in Functions
A list of built-in functions which are already implemented and registered within SurveyJS Library is given below.
iif
iif(condition: expression, valueIfTrue: any, valueIfFalse: any): any
View source
Returns the value specified by valueIfTrue if the given condition is truthly and the value specified by valueIfFalse if the condition is falsy. The condition is an expression that can contain typical operands/operators and references to question values (as question names in curly brackets).
Example:
expression: "iif({question1} + {question2} > 20, 'high', 'low')"
isContainerReady
isContainerReady(nameOfPanelOrPage: string): Boolean
View source
Returns true
, if all questions in the specified container (panel or page) are answered correctly (a respondent provided a valid input). This function recursively validates all questions in the container. If there is an error, the function returns false
, otherwise true
. In case a question's value is empty and neither validators no required status are defined for the editor, validation would pass successfully.
Example:
expression: "isContainerReady('page1')"
isDisplayMode
isDisplayMode(): Boolean
View source
Returns true
if a survey is in display mode.
Example:
expression: "isDisplayMode()"
age
age(birthDate: any): number
View source
Returns the age according to the date of birth passed. The passed date value (which is typically taken from the referenced question) should be defined as a valid JavaScript Date.
Example:
expression: "age({birthdate})"
currentDate
currentDate(): Date
View source
Returns the current date.
Example:
expression: "currentDate()"
today
today(daysToAdd?: number): Date
View source
Returns the current date or a date calculated using an optional parameter. The parameter specifies the number of days to be added to the current date. For example, "today()" returns the current date 0 hours, 0 minutes, "today(-1) returns yesterday's date, "today(1)" returns tomorrow's date, "today(2) returns day after tomorrow date, and so on.
Examples:
expression: "today()"
expression: "today(2)"
getDate
getDate(questionName: expression): Date
View source
Returns the specified question's date value.
Example:
expression: "getDate({dateQuestionForBirthday})"
diffDays
diffDays(dateFrom: any, dateTo: any): number
View source
Returns the number of days between two dates. Dates are typically specified by expressions that correspond to questions (by their names in curly brackets) containing date values.
Example:
expression: "diffDays({startDate}, {endDate}) < 7"
sum
sum(par1: number, par2: number, ...): number
View source
Returns the sum of the passed arguments.
Example:
expression: "sum({total1}, {total2})"
max
max(par1: number, par2: number, ...): number
View source
Returns the largest value from a list of the passed arguments. From v1.5.19.
Example:
expression: "max({total1}, {total2})"
min
min(par1: number, par2: number, ...): number_
View source
Returns the largest value from a list of the passed arguments. From v1.5.19.
Example:
expression: "min({total1}, {total2})"
avg
avg(par1: number, par2: number, ...): number
View source
Returns the average value of the passed arguments.
Example:
expression: "avg({total1}, {total2}, {total3})"
sumInArray
sumInArray(questionName: expression, propertyName: string): number
View source
Returns the sum of values in a array taken from the specified question property (both - the question and its property - are referenced by their names).
Example:
expression: "sumInArray({matrixdynamic1}, 'total') > 1000"
View code sample
maxInArray
maxInArray(questionName: expression, propertyName: string): number
View source
Returns the maximum of all values in an array specified by a property (propertyName) of a matrix question (questionName specified as the question name in curly brackets).
Example:
expression: "maxInArray({matrixdynamic4}, 'quantity') > 20"
minInArray
minInArray(questionName: expression, propertyName: string): number
View source
Returns the minimum of all values in an array referenced by a property (propertyName) of a matrix question (questionName specified as question name in curly brackets).
Example:
expression: "minInArray({matrixdynamic3}, 'quantity') > 5"
avgInArray
avgInArray(questionName: expression, propertyName: string): number
View source
Returns the average of all values in an array referenced by a property (propertyName) of a matrix question (questionName specified as question name in curly brackets).
Example:
expression: "avgInArray({matrixdynamic2}, 'quantity') > 10"
countInArray
countInArray(questionName: expression, propertyName: string): number
View source
Returns the total number of items in an array referenced by a property (propertyName) of a matrix question (questionName specified as the question name in curly brackets).
Example:
expression: "countInArray({matrixdynamic5}) > 10"
If you feel there is a need in a particular function, then write us about it.
Custom Functions
You can write, register, and use your own functions in expressions.
Implementation rules
The following basic rules exist:
Use a valid function name
A function's name should be in lower camel case (e.g.myCustomFunction
).Use a single array-like parameter for arguments
A function's argument objects should be passed and processed within the function as a single parameter - an array-like object containing the values of the passed arguments.As an example, consider a custom function that accepts more than one parameter and is called with the following syntax in an expression.
expression: "myFunc({question1}, {question2})"
The function should be implemented in the following manner:
function myFunc(params) { let q1_value = params[0]; let q1_value = params[1]; ... }
instead of:
function myFunc(q1_value, q2_value) { }
Otherwise, the function will not work.
Register your custom function
You should register your custom function to make it usable within SurveyJS expressions. Use theFunctionFactory.Instance.register
method to register a function.
This method has the following signature:
FunctionFactory.Instance.register(funcName: string, func: any, isAsync?: boolean = false);
- funcName - the function name,
- func - a reference to the function,
- isAsync - whether the function is asynchronous.
Usage example:
function myFunc(params: any[]): any { ... } // Function registration FunctionFactory.Instance.register("myFunc", myFunc); function myAsyncFunc(params: any[]): any { ... } // Registration of async function FunctionFactory.Instance.register("myAsyncFunc", myAsyncFunc, true);
Access survey element instances inside a custom function
Inside a custom function's implementation, you have access to the entire survey object through this.survey
(available from v1.0.21).
As a result, you are able to access any element (and its values) within a survey.
You can design your custom function so that it accepts the name of a survey element (e.g. a question, panel, or page) as a parameter and then, inside the function, you can use this name to get an instance of the corresponding element.
For example, a question's name can be passed as a function parameter:
myFunc('myQuestionName')
And you can obtain the question's instance inside the function in the following manner:
questionInstance = this.survey.getQuestionByName(params[0]);
Use Asynchronous Functions in Expressions
In SurveyJS expressions, you may require to perform some external and time-consuming calculations, and/or return a result from a server. In such cases, SurveyJS has to perform the following sequence of actions:
- make a request to a web service,
- wait until the service returns the result,
- continue to evaluate the expression based on the result returned.
Calling a web service and getting the result from it is an asynchronous operation. If there is one asynchronous operation in your flow, then all operations that relies on such an asynchronous operation should also be asynchronous.
To manage asynchronous behavior and flow control, SurveyJS allows you to implement and register asynchronous custom functions. Note that to support IE browsers, SurveyJS uses a ES5 (ECMAScript 5 asynchronous callback technique (not promises).
The code sample below illustrates the key points in asynchronous function implementation:
function asyncFunc(params: any[]): any {
var self = this; // Store the context for this.returnResult callback
setTimeout(function() {
// Return the value via a callback
self.returnResult(yourValue)
}, 100);
return false; // The return value is ignored.
}
// The third parameter specifies that the function is asynchronous
FunctionFactory.Instance.register("asyncFunc", asyncFunc, true);
The following code example demonstrates how to implement and register a custom asynchronous function (isCountryExist). In the example, this function is used in a text question's validator of the expression type.
async function isCountryExist(params) {
if (params.length < 1) {
this.returnResult(false);
return false;
}
var countryName = params[0];
var self = this;
var res = await $.ajax({
url: "https://surveyjs.io/api/CountriesExample?name=" + countryName
}).then(function(data) {
var found = data.length > 0;
self.returnResult(found);
});
return false;
}
Survey.FunctionFactory.Instance.register(
"isCountryExist",
isCountryExist,
true
);
// The isCoutryExist function is used in the question validator's expressions.
var json = {
questions: [
{
type: "text",
name: "country",
title: "Type a country:",
validators: [
{
type: "expression",
expression: "isCountryExist({country})", // Function usage
text: "Please type the country correctly!"
}
]
}
]
};
var survey = new Survey.Survey(json);
Example
See the example's full code:
Async Function in Expression
Cascade Conditions
Example. The first question is "Do you have children?" (hasChildren) and the second question is "How many children do you have?" (kidsCount). The second question has the following visbileIf
expression: "{hasChildren} = 'yes'"
. Then you display dropdowns with questions: "The first kid age", "The second kid age" and so on. Their visibleIf
expressions are as follows:
"{hasChildren} = 'yes' and {kidsCount} >= 1"
,
"{hasChildren} = 'yes' and kidsCount >= 2"
and so on.
In this example, the additional {hasChildren} = 'yes'
condition is added to "{kidsCount} >= 1"
, because of the following:
- A user answers the "Do you have children?" question 'yes' and "How many children do you have?" to 2.
- A user answers the first question 'no'.
- The second question becomes invisible, but its value is still 2 and the questions about kids' age are still shown, unless you add
"{hasChildren} = 'yes'"
condition.
SurveyJS allows you to avoid additional conditions in cascade questions. Set the survey.clearInvisibleValues property to onHidden
to clear values for invisible questions.
In the example above, on making "How many children do you have?" question invisible, its value would be cleared. As a result, the value becomes undefined and you can simplify the expression to: "{kidsCount} >=1"
.
You can play with the Cascade Conditions example to see the survey.clearInvisibleValues property use in action.
Dynamically Filter Choices, Columns, and Rows
SurveyJS allows you to control which answer options are visible based on previous choices in a survey.
Method #1: Specify Visibility Conditions for Individual Options
Example. A user can select multiple communication channel options. The "Text Messages" and "WhatsApp" options appear only if a user has entered their phone number in a previous question.
You can implement this behavior without writing any code. SurveyJS exposes the visibleIf property for answer choices:
choices: [
"Email",
{ value: "Text Messages", visibleIf: "{phone} notempty"},
{ value: "WhatsApp", visibleIf: "{phone} notempty"}
]
Method #2: Display Options Selected in Previous Questions
Questions in this example progressively filter out browsers based on user answers.
Here's the logic breakdown.
Display the complete browser list.
name: "installed", choices: ["Chrome", "MS Edge", "FireFox", "Internet Explorer", "Safari", "Opera"]
Display only browsers checked in the previous question.
name: "default", choicesVisibleIf: "{installed} contains {item}", choices: ["Chrome", "MS Edge", "FireFox", "Internet Explorer", "Safari", "Opera"]
SurveyJS iterates all "choices" and substitutes each as an "" into
choicesVisibleIf
. Only choices that make the expressiontrue
appear in the list.Display browsers checked in #1, exclude browser that matches #2.
name: "secondChoice", choicesVisibleIf: "{installed} contains {item} and {item} != {default}", choices: ["Chrome", "MS Edge", "FireFox", "Internet Explorer", "Safari", "Opera"]
Examples
Fill the Choices From a Restful Service
SurveyJS can populate choices/items in a drop-down list, check boxes, and radio groups with items obtained from a web service.
Example
The online Survey Creator allows you to configure a connection to a web service with a dialog:
Choices By Url Property Editor
Property Name | Description |
---|---|
url | A link to a web service. You may use the text preprocessing here. For example, the following url: https://surveyjs.io/api/CountriesExample?region={region} is changed based on the region question value. SurveyJS automatically gets data from web service on changing the region value. |
path | Use this property, if a web service returns a lot of information and you need only a part of it. For example, the service returns the list of countries and list of capitals. If you need a list of countries, set a correct path from which SurveyJS obtains the data, like: DataList1\DataList2 |
valueName | The property name in your obtained data, that SurveyJS should bind with the value. |
titleName | The property name in your obtained data, that SurveyJS should bind with the text. It can be empty. |
Note
During the user session, if the same URL is requested, SurveyJS returns data from a cached list and does not send another request.
You can control the process of setting choices into a question from the web service by handing the onLoadChoicesFromServer event. The options parameter in this event has three properties:
- question - the question where choices are loaded
- choices - the list of loaded choices that library fills automatically
- surveyResult - the result object that comes from the web service
Readonly and EnableIf Expression
Questions, matrix dropdown, and matrix dynamic columns have the enableIf property. It works exactly like visibleIf, except it makes control enable/disable instead of visible/invisible. It is useful when you do not want to change your layout and want to make sure that all questions are always visible, but still want to make it impossible for your users to answer some questions.
Example
Since v1.0.31, we have introduced the readOnly and enableIf property into Panel and Page objects. They work like the same properties in Question object. The only difference, since these objects are containers, then all children (Panels and Questions) inside them becomes read-only if their parent is read-only.
Text Processing, Dynamic Titles, and HTML Properties
The following survey elements support text processing:
- pages,
- panels,
- question titles,
- question description,
- survey completedHtml and loadingHtml properties,
- html property in html question.
It means you can set a question title as: "{name}, could you please provide us your e-mail?"
, where the name is the question name or a calculated value name.
Note
SurveyJS uses a question's display name. In questions, like dropdown, the display name and value name may differ (e.g., value can be "UK" and the display name is "United Kingdom").
Question Numbers
You can control the question numbering. All questions titles show question numbers by default: from 1 to the visible question number in the survey. You can hide question numbers by setting survey.showQuestionNumbers property to off
, or start the numbering from the beginning on each page, by setting this property to onPage
.
You may use alphabet numbering by setting survey.questionStartIndex property to A.
or a.
.
You can add prefix and change the postfix (default is dot) for this property, for example: # (1)
or (A)
.
Question Required Mark
Use the survey.requiredText property to change the required symbol. SurveyJS uses the asterisk (*
) symbol by default. You can change it to another text or make it empty.
Example
Calculated Values
Since v1.1.10 you may use calculated values in your text processing. Calculated Value item has three writable properties:
- name (it should be unique),
- expression (value read-only property is calculated based on this expression),
- includeIntoResult (a Boolean property,
false
by default. Set it totrue
, to include it intosurvey.data
). It has one read-only property: value (calculated automatically based on expression).
Example
Client and Server-Side Validation
Before proceeding to the next page or before completing the survey, the SurveyJS Library validates all questions on the current page. If there is an error, the current page is not changed, all errors are shown and the input, the first of invalid questions is focused.
If you want to validate the value and display an error immediately after a user entered the value into the question, change the survey.checkErrorsMode property from the default onNextPage
to onValueChanged
.
survey.checkErrorsMode = "onValueChanged";
Since v1.1.10, SurveyJS supports async expressions. You may add your own async custom functions into the library that your users can use to create surveys.
Standard Validators
The simplest and most used validation is a required value. You must set question.isRequired to true
and SurveyJS will require the user answer the question. In SurveyJS Creator, toggle exclamation mark (!) to make a question required. To override the error text on required error, change the survey requiredText property.
Except required validation, there is a list of built-in validation classes, that you may use by adding them into question.validators array property. For example, the following code adds a validation for e-mail input:
question.validators.push(new Survey.EmailValidator());
The same code in JSON will be as:
validators: [{ type: "email"}]
To change the default error text, you must set the validator text property.
Here is the list of standard validators
Name | Validator Class | Description |
---|---|---|
numeric | NumericValidator | Raises an error if the question answer is not a number, or if an entered number is outside the minValue and maxValue range. |
text | TextValidator | Raises an error the entered text length is outside the minLength and maxLength range. |
expression | ExpressionValidator | Raises an error when the expression returns false . Use the expression property to specify the validated expression. This validator was added in v1.0.23. The following expression validator raises error if the summary is less than 100: expression: "{price} \* {quantity} >= 100" . |
answercount | AnswerCountValidator | Works for questions which value is array, for example: checkbox. Raises an error if a user selects less choices that minCount (if minCount defined) or more than maxCount (if maxCount is defined). |
regex | RegexValidator | Raises an error, if the entered value it does not fit the regular expression defined in the regex property. |
EmailValidator | Raises an error, if the entered value is not a valid e-mail. |
Example
Custom Validation
SurveyJS allows you to handle the onValidateQuestion event to implement custom validation logic.
The following code demonstrates how to display an error message if the value in rateMe is not in the rage from 1 to 9.
survey.onValidateQuestion.add(function(sender, options) {
if(options.name == "rateMe") {
if(options.value < 1 || options.value > 9) options.error = "Please enter value from 1 till 9.";
}
});
Example
Custom Validators
You may implement your own validator, if you want to use it in SurveyJS Creator, for example, or going to use it in your surveys.
Example
Validate Results on Server
Sometimes, there is no way you may validate the answers on the client and validation should be performed on your backend or you must call an ajax function to get an additional information.
Example
survey.onServerValidateQuestions.add(function(sender, options) {
// question values on the current page have the following format: 'questionName: value'
// Send the 'options.data' json object to your server.
// To specify errors on the current page, set the 'options.errors' json object as "questionName": "ErrorText".
// Leave it empty, if there is no error on the current page.
// Call the 'options.complete()' function to tell the survey that your server callback has been processed
// options.data contains the data for the current page.
var countryName = options.data["country"];
// If the question is empty then do nothing
if (!countryName)
options.complete();
//call the ajax method
$
.ajax({url: "https://surveyjs.io/api/CountriesExample?name=" + countryName})
.then(function (data) {
var found = data.length > 0;
//if the country is unknown, add the error
if (!found)
options.errors["country"] = "The country name '" + countryName + "' is not in this list: https://surveyjs.io/api/CountriesExample";
//tell survey that we are done with the server validation
options.complete();
});
});
Localization and Multilanguage Support
At the current moment, strings of SurveyJS UI elements are translated into more than 30 languages. The localization is supported by the community.
Available Translations
To see a list of all available translations, open the SurveyJS Creator, click on the "Survey Settings" button, and then, within the PROPERTIES window's General tab, open the Default language property's dropdown window.
Each translation is implemented in a separate locale-specific file. You can view translation files in the localization folder in our sources. To localize SurveyJS to your own language, read the instruction in the folder's readme file.
Switch Locales
Use the survey.locale property at runtime to change the survey locale.
// Sets Spanish locale
survey.locale="es";
Translate Individual Strings
If any strings are not translated into your language, or you want to translate them in a different way, you can change the translation on-the-fly using the following approach:
var mylocalization = Survey.surveyLocalization.locales["localename"];
mylocalization.stringName = "My new localized string";
You can find a list of all localizable strings in the default English localization.
For an example, the following code sample shows how to modify texts of the "Previous Page" and "Next Page" navigation buttons for the English locale.
//Modify strings for the 'en' locale.
var myloc = Survey.surveyLocalization.locales["en"];
myloc.pagePrevText = "My Page Prev";
myloc.pageNextText = "My Page Next";
The sample code below demonstrates how to define and add to the library a custom locale with the modified texts of the "Previous Page" and "Next Page" navigation buttons and the "Complete" button.
//Add a new locale into the library.
var mycustomSurveyStrings = {
pagePrevText: "My Page Prev",
pageNextText: "My Page Next",
completeText: "OK - Press to Complete"
};
Survey
.surveyLocalization
.locales["my"] = mycustomSurveyStrings;
See Example: Localization
Create a Multilanguage Survey
SurveyJS allows you to create a single survey for multiple languages at the same time. To switch between locales, change the survey.locale property.
All strings in a survey JSON have the following declaration:
text: "Some text"
Most of strings in SurveyJS are localizable and you are able to write multiple localizations directly into a JSON. In JSON, localizations of string properties can be defined as key/value pairs, where the key is a locale and the value is a required translation.
The following code sample demonstrates how to define the text
property's localization in a JSON to return "Dog" for all languages except German, and to return "Der Hund" for the German locale ("de").
text: { "default": "Dog", "de": "Der Hund" }
Note that the definition text: {"default: "Dog"}
has the same result as text: "Dog"
.
If there is no translation for the selected locale, the default value is used, or the first one, if "default" does not exist.
To work with strings of the default locale (in code, or in Survey Creator) set the survey.locale property to an empty string.
See Example: Multiple Languages in a Survey
choicesByUrl Localization
When choices for a QuestionSelectBase-derived question (a checkbox, dropdown or radiogroup question) are loaded from a RESTful service (specified via a question's choicesByUrl property), SurveyJS is able to recognize and apply text localizations of choices if choice items are defined in the following format within the obtained JSON:
{
value: "item",
title: {
en: "item in English",
de: "item in Deutch"
}
}
See Plunker Sample: choicesByUrl Localization
Extend SurveyJS Elements by Adding Properties
Since this topic is mostly for our Survey Creator users, it is described in the Survey Creator Documentation. However, for some scenarios, the described functionality maybe useful for SurveyJS Library without using the Creator.
Triggers: Control the Survey Logic
SurveyJS triggers help you to implement some logic in your surveys without writing JS code.
Every trigger has the expression property. On changing a value, if this value is used in the expression, then the expression is running. If the expression returns true
, then the trigger executes the function, a success function, that make a change(s) in the survey logic.
Every trigger type overrides this success function in its own way.
Available Triggers
complete
Complete the survey if the expression returns true
. It performs on changing the current page into the next.
The following trigger completes the survey if the question "age" on this page will have value less than 18.
{ "type": "complete", "expression": "{age} < 18" }
setvalue
If expression returns true
, then copy a value from the setValue property into the setToName value/question.
The following triggers set the value "ageType" to child or adult based on the "age" question.
[{ type: "setvalue", expression: "{age} < 18", setToName: "ageType", setValue: "child" },
{ type: "setvalue", expression: "{age} >= 18", setToName: "ageType", setValue: "adult" }]
copyvalue
It works like the setvalue trigger. It takes a value from a question fromName and copy it into setToName.
The following trigger copies the billing address into delivery address if the question "Shipping address same as billing" is set to "Yes".
{ "type": "copyvalue", "expression": "{sameAsBilling} = 'Yes'", setToName: "shippingAddress", fromName: "billingAddress" }
runexpression
If the expression is successful, then it runs the expression in the runExpression property. If the property setToName is not empty, then the result of the runExpression would be set into this value.
Here is the example of using this trigger.
visible
Obsolete, use the visibleIf property instead.