Custom JavaScript

Introduction

JavaScript is a powerful programming language that enables you to add and extend functionality already built into Discover. Custom JavaScript is only available to users with active subscriptions.

Numerous online resources are available to guide you in mastering JavaScript and implementing the desired changes to your surveys.

To add JavaScript to your survey, navigate to the Custom JavaScript section in the Settings tab.

Enter custom code by going to the settings section of the survey.

Discover’s survey runtime is a single-page application. This means that the browser sends the initial request for the page, but all subsequent navigation and rendering is handled in the browser via JavaScript. Due to the nature of this paradigm, any custom JavaScript added to your survey will only be executed on the initial page load when the respondent navigates to your survey URL unless you use Discover’s built-in system hooks.

In your JavaScript, you can use defined variables and built-in scripting functions to retrieve data, responses, and other useful metadata.

Functions

JavaScript functions can be defined using the default function syntax or the arrow function syntax.

// returns a random integer from 0 to rangeMax

function getRandomInt_V1(rangeMax) {
  return Math.floor(Math.random() * rangeMax);
}

// returns a random integer from 0 to rangeMax

const getRandomInt_V2 = (rangeMax) => {
  return Math.floor(Math.random() * rangeMax);
}

Functions can be used within your custom JavaScript and in text fields throughout your survey using scripting.

Using Java Script Functions

Variables

Variables are used to store data as respondents take the survey. Create new variables in the Variable manager.

After creating a variable, you can assign values to it in your custom JavaScript by using the “=” operator:

myVariable = getValue("Q1") + 10;

Variables can then be accessed anywhere that supports scripting by using the variable name:

myVariable

In the example above, assuming the value of Q1 was 5, “15” would print to the screen. Variables can be used in many places throughout Discover, such as survey endings, skip logic and quota control.

Example

We have a survey with two numeric questions:

  • Question 1 (“Purchase Question”) asks the respondent how many donuts they purchase at a time.
  • Question 2 (“Days Per Week Question”) asks how many days a week they typically buy donuts.

We want to store the number of donuts the respondent buys per week, so we have added a variable in the Variable manager called “donutsBought.” We can then use this variable to store a value either on the same page as the questions or on another page after they have been answered:

{{ donutsBought = getValue("Purchase Question") * getValue("Days Per Week Question"); }}

The total value will be saved when the page containing the code above is submitted by the respondent.

Currently, Discover only allows for strings to be saved, so any numbers (like “donutsBought” above) will be converted to a string in the database. If you want to use this value as a number elsewhere in JavaScript, you must convert it to a number first (this can be achieved by using a function such as parseInt). This also means we do not currently support numerical comparisons in places like skip logic (skip if donutsBought > 10).

Additionally, you cannot assign variables values on Survey endings. Once a respondent reaches a Survey ending, text can be displayed, but variables cannot be assigned values.

System hooks

To help you extend the functionality of your survey, Discover offers a series of functions that allow you to hook into system events.

addOnQuestionLoadHandler

addOnQuestionLoadHandler(questionName: string, callback: (element?: HTMLElement) => void);

This function can be used to run JavaScript when a specific question is rendered on the page.

This function accepts two parameters:

  1. The question name that the function will apply to.
  2. The callback function. For convenience, your callback function can accept a reference to the HTML element that contains the question, but it is optional.

Here is an example of how this function may be written:

// this will run custom script when a question is loaded on the page
addOnQuestionLoadHandler("Q1", (questionElement=> {
  // your custom code goes here
  // this will show a pop-up when Q1 loads in the browser
  alert("Q1 has loaded!");
});

addPostValidationHandler

addPostValidationHandler(questionName: string, callback: () => QuestionError | QuestionError[]);

This function can be used to add custom validation to a question that will run after the default validation runs.

This function accepts two parameters:

  1. The question name that the validation will apply to.
  2. The validation function.

There are several valid return types you can use that will indicate the question is in an error state:

  • null No errors were found, and no errors will be displayed.
  • undefined No errors were found, and no errors will be displayed.
  • string An error was found, and the error will be displayed above the question.
  • { error: string } An error was found, and the error message will be displayed above the question.
  • { error: string, itemNumber: number } An error was found, and the error message will be displayed above the list item that the error pertains to. (This only applies to single and multi-select questions, constant sum questions, and ranking questions.)
  • { error: string, rowNumber: number, columnNumber?: number } An error was found, and the error message will be displayed above the row that was provided. If a column is also provided, then error formatting will only apply to the specific cell indicated. (This applies only to grid questions.)

If you want to display multiple errors, you can return an array of any of the above types.

Here is an example of how this function may be written:

// this example runs custom validation on Q1 after system question validation runs
addPostValidationHandler("Q1", () => {
   
  // get the value of Q1 and assign it to a variable
  const q1Value = getValue("Q1");
  
  // if system validation has passed and this statement is true respondents will see your error message
  if (q1Value > 100) {
    // put error message here
    return "Please enter a number between 0 and 100.";
  }
});
To look at the current response to your question, you can use the getValue function.

addPreValidationHandler

addPreValidationHandler(questionName: string, callback: () => QuestionError | QuestionError[]);

This function can be used to add custom validation to a question that will run before the default validation runs.

The parameters and types are the same as addPostValidationHandler.

Generally, you should use a post-validation handler instead of a pre-validation handler. Doing this allows you to take advantage of Discover’s built-in validation (such as verifying a question has a response) before your code is run.

Here is an example of how this function may be written:

// this example runs custom validation on Q1 before system question validation runs
addPreValidationHandler("Q1", () => {
  
  // get the value of Q1 and assign it to a variable
  const q1Value = getValue("Q1");
 
  // if this statement is true, respondents will see your error message and system question validation will not run
  if (q1Value > 100) {
    // put error message here
    return "Please enter a number between 0 and 100.";
  }
});

Debugging

It is imperative that you test your code before publishing your survey. Use the Test button to see how the code you have written will behave when respondents take your survey. See this article for tips on debugging JavaScript.

⚠️ IMPORTANT ⚠️ 

Make sure to handle errors in your own code. If an error is thrown inside your code, survey respondents will be routed to an error page and will not be able to continue taking the survey. 

Survey updates

Discover is a live service, regularly receiving automatic security and design updates each week. When either CSS or JavaScript is used, we "freeze" these automatic updates to prevent them from unintentionally interfering with your code. Though updates are not given automatically at this point, surveys are given the latest improvements every time the survey is republished.

If you are using code, before publishing we strongly encourage you to use the test functionality in Discover and run through the parts of your survey that include custom code to ensure there are no unintended interactions.

Note: To maintain the safety and security of Discover, surveys with custom code that haven’t been published in six months will be updated to receive the latest improvements.

Code library

The Sawtooth Software Community includes other examples of JavaScript that can be used in your survey. Visit the community.