psychopy.org | Reference | Downloads | Github

Custom web component for online experiments: Forms, surveys, questionnaires, and other web-based content

While Pavlovia/PsychoJS is seeing increased interest recently, some of PsychoPy’s components have not yet been implemented online. Additionally, there may always be an interest in custom components for online experiments even after all PsychoPy features are ported.

Of particular interest are PsychoPy’s form components, as the majority of IRB-approved online experiments require consent forms, demographic surveys, and feedback questionnaires, for example. However, forms functionality and rating scales are not currently available online.

Available options to consider:

  1. Make do with existing features: For example, use the Keyboard component for consent, the Slider component for demographics, multiple text inputs for surveys, custom coding for free-text inputs, etc. It is also possible to use the info dialog for demographics, though not in experiments that require consent first.
  2. Use something like Qualtrics instead: For example, it is possible to have a workflow such as Qualtrics -> Pavlovia -> Qualtrics if you want to have Qualtrics (or similar tool) handle consent and/or debrief, while Pavlovia handles only the core experiment component.
  3. Build a custom web component.

For the experiment I worked on, I decided to build a custom web-based component using good-old HTML/CSS and some Javascript (jQuery). If you would like to do the same for your experiment, then follow the steps below.

Note: I would not recommend this approach for anyone not familiar with web development. When PsychoJS catches up to PsychoPy, I would expect the built-in functionality to be far superior in terms of ease of use, cross-platform compatibility, and integration. Experienced web-developers know what it’s like to build that from scratch.

  1. Find Find and sync+fork (download) my sample project Custom Web Component from Pavlovia to PsychoPy, or download the experiment files directly from GitLab.
  2. Open the experiment (web-component.psyexp), and select any routine (they are all the same).
  3. Copy the routine (Experiment > Copy Routine) and paste it into your own experiment (Experiment > Paste Routine).
  4. Click the _code component in the routine, select the Begin Routine tab, and change the file name in the first line of code to your own html file.
  5. Create your own html file as desired, and place it in the html directory of your project.

Run the experiment using local debug mode to see how it works. The web component routine automatically includes the html file as an iframe, and usually requires no additional configuration.

The provided code automatically adjusts the iframe width and height to match its contents, centers it in the screen, and adds a vertical scrollbar if needed. It also automatically detects and handles a form within the file. If you require something more sophisticated (eg, multiple forms, or multi-step forms), then you will need to modify this code, but otherwise, it should just work. Feel free to use any of the provided sample html files as starting points.

One advantage of this approach is the ability to insert any custom web-based content (not just forms) anywhere in the experiment (eg, Consent -> Experiment Part 1 -> Distraction Survey -> Experiment Part 2 -> Debrief). The main advantage however, is the ability to include any custom web-based content not currently implemented in PsychoJS.

5 Likes

This sounds awesome. I can’t wait to try it out (though I’ll probably still use Qualtrics for PI sheets since I’m using it for balanced allocation to conditions.

This is great to show people how to add their own custom forms/JS

We do actually expect to have basic forms working online in the next release (2020.2) in July.

Although the class called RatingScale isn’t available that doesn’t mean you can’t provide rating scales. Slider achieves the same and more functoinality and that does work online. RatingScale is not supported specifically because it’s less flexible than Slider.

I’ve been playing about with this but I haven’t figured out how to pass the form variables back to PsychoPy.

My form (from https://pavlovia.org/Wake/brookes-template-2020) looks like this:

<form name="form1" method="post" action="">
  <h2 class="style1">Embedded Form </h2>
  <p class="style1">Which of the following demos would you like to see?<br>
Unfortunately this functionality doesn't yet work.</p>
  <table border="0">
    <tr>
      <td class="style1">Random Seed demo</td>
      <td class="style1"><input name="showSeed" type="checkbox" id="showSeed" value="1"></td>
    </tr>
    <tr>
      <td class="style1">Embedded YouTube video </td>
      <td class="style1"><input name="showVideo" type="checkbox" id="showVideo" value="1"></td>
    </tr>
    <tr>
      <td class="style1">Slider</td>
      <td class="style1"><input name="showSlider" type="checkbox" id="showSlider" value="1"></td>
    </tr>
    <tr>
      <td class="style1">Loop which repeats incorrect trials </td>
      <td class="style1"><input name="showLoop" type="checkbox" id="showLoop" value="1"></td>
    </tr>
    <tr>
      <td class="style1">Age text entry </td>
      <td class="style1"><input name="showAge" type="checkbox" id="showAge" value="1"></td>
    </tr>
  </table>
  <p>
    <span class="style1">
    <input type="submit" name="Submit" value="Submit">
  </span> </p>
</form></center>

I’m assuming that there should be a way since you can record the values to the data file. Do I need to address the trial handler in some way?

My closest attempt so far is

showSlider = psychoJS.experiment._trialsData.map((trial) => trial['showSlider']);

This returns an empty array, even if I put an nRep=1 loop around the Routine.

@wakecarter Placing the following in the End Routine tab gives me non-empty results:
console.log ( 'DEBUG:FRM', psychoJS.experiment._currentTrialData );

I have also added a params object to the code (download the latest version for that) - eg:
showSlider = psychoJS.experiment._currentTrialData['showSlider'];
or
showSlider = params['showSlider'];
But just note that params is reset in each Routine, while _currentTrialData would be reset at each trial loop.

1 Like

Thank you. That worked and I’ve also managed to work out how to send a variable to the form from PsychoPy using code from https://html-online.com/articles/get-url-parameters-javascript/

This is brilliant, thanks for sharing it !!! :smiley: