Cart Buy Licenses Contact Integrate into App Docs Support Login/Register
v 1.8.68
v 1.8.68
Overview Examples Docs Source Download

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

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:

  1. Register on SurveyJS web site.

  2. Create a new Survey in the SurveyJS Service.

  3. In the SurveyJS Service page, copy your Survey Id.

    get survey id

  4. 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

Demo: Load a survey from SurveyJS Service.

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:

  1. Register on SurveyJS web site.

  2. 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.

  3. Get a Post Id for a new survey:

    survey get post id

  4. 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

Save survey results in SurveyJS backend

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

Patient Medical History

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:

  1. 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).
  2. 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

Custom Navigation

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

Go to the next page automatically

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:

  1. Use a valid function name
    A function's name should be in lower camel case (e.g. myCustomFunction).

  2. 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.

  3. Register your custom function
    You should register your custom function to make it usable within SurveyJS expressions. Use the FunctionFactory.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://restcountries.eu/rest/v2/all"
  }).then(function(data) {
    var found = false;
    var countries = data;
    for (var i = 0; i < countries.length; i++) {
      if (countries[i].name == countryName) {
        found = true;
        break;
      }
    }
    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:

  1. A user answers the "Do you have children?" question 'yes' and "How many children do you have?" to 2.
  2. A user answers the first question 'no'.
  3. 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 expression true 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

Get choices from a web service

The online Survey Creator allows you to configure a connection to a web service with a dialog:

Choices By Url Property Editor

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://restcountries.eu/rest/v2/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

Condition - Enable/Disable Elements

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

Process Text

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 to true, to include it into survey.data). It has one read-only property: value (calculated automatically based on expression).

Example

Use calculated values

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.
email 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

Event Validators.

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

Custom Validators.

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

Server Validators.

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://restcountries.eu/rest/v2/all"})
        .then(function (data) {
            var found = false;
            var countries = data;
            for (var i = 0; i < countries.length; i++) {
                if (countries[i].name == countryName) {
                    found = true;
                    break;
                }
            }
            //if the country is unknown, add the error
            if (!found)
                options.errors["country"] = "The country name '" + countryName + "' is not in this list: https://restcountries.eu/rest/v2/all";

            //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.