Replies: 21 comments 72 replies
-
Hi Josh! I'm making an experiment with jsPsych and JATOS and am migrating my experiment to v7.0. I've started with one of my simple components, a Break trial, and I think it's going okay, but I'm getting an error from the part where I pass data to JATOS. Here is my error message:
And here is my component code: <!DOCTYPE html>
<html>
<head>
<title>Odd One Out break</title>
<!-- These lines import all script sources, including the jsPsych JavaScript library, any plugin files
used, any supplemental files (e.g. stimuli lists for test trials, functions that are shared across multiple
components), the jsPsych CSS, and JATOS scripts. Most of these are contained within the study folder, and
so the full file path is not required at the beginning. -->
<script src="jspsych/jspsych.js"></script>
<script src="jspsych/plugin-html-button-response.js"></script>
<script src="js/functions.js"></script>
<link href="jspsych/jspsych_edited.css" rel="stylesheet" type="text/css"></link>
<script src="/assets/javascripts/jatos.js"></script>
</head>
<body></body>
<script>
var jsPsych = initJsPsych({
preload_audio: ['audio/bloop.mp3'],
on_data_update: function(data){ // on_data_update saves data after each trial and sends it to JATOS when the browser is closed
var studyID = jatos.studyResultId; // grabs Result ID generated by JATOS
this.jsPsych.data.addProperties({subject_id : studyID}); // adds subject column to data with Result IDs
var resultsRaw = this.jsPsych.data.get();
var results = resultsRaw.ignore('stimulus').ignore('trial_type').ignore('internal_node_id').ignore('time_elapsed'); // if you want to ignore certain columns in the output so the data output is a bit cleaner, doesn't include the "intern_node_id" or "time_elapsed" columns" in the output in this case
var resultsCSV = results.csv(); // convert results output to CSV
jatos.submitResultData(resultsCSV); // sends data to JATOS when the browser is closed
},
on_finish: function (data) { // on_finish will overwrite any data saved from on_data_update if all of the data gets sent in at the end
var studyID = jatos.studyResultId;
this.jsPsych.data.addProperties({subject_id : studyID});
var resultsRaw = this.jsPsych.data.get();
var results = resultsRaw.ignore('stimulus').ignore('trial_type').ignore('internal_node_id').ignore('time_elapsed');
var resultsCSV = results.csv();
jatos.submitResultData(resultsCSV, jatos.startNextComponent);
}
})
/* Initialize a general timeline for the component */
var timeline = [];
/* Create variable(s) containing button audio */
var bloop = new Audio("audio/bloop.mp3"); // for navigation buttons
/* Instructions page for the participant/their parent. */
var pause = {
type: jsPsychHtmlButtonResponse,
stimulus: "<span style='font-size:2vw;'><p><b>Great work!</b></p><p>This is a good time for a break. Take as long as you like before continuing.</p><p>Please leave this window open while you do so.</p></span>",
choices: ['Continue >'],
button_html: '<button style="position:fixed; width:11vw; left:calc(50vw - 7.5vw); bottom:0; margin:2vw;" class="jspsych-btn"; onclick=bloop.play()>%choice%</button>', // specify fixed width, calc for left should be 50vw (50% across screen) minus half width and 10 px (half the margin value)
data: {
test_part: 'pause_break'
},
post_trial_gap: 240, // inserted to allow the navigation button noise to finish
};
timeline.push(pause);
/* Start experiment and send results back to JATOS when it is done. */
jatos.onload(function() {
jsPsych.run(timeline);
});
</script>
</html> Do you have any thoughts about what I should change? Thank you for any help you can offer. |
Beta Was this translation helpful? Give feedback.
-
Hi Josh, I have another question! For my experiment, I'm using the image-button-response plugin, but previously I'd modified it to add an "I don't know" button that would appear after a minute of no response, following Becky's advice in threads #1294 and #1786 . I successfully made a copy of the plugin file and re-named it to match my study ("plugin-odd-one-out"/"jsPsychOddOneOut"), and tried to migrate the same changes into it, but I'm not sure where to put them within the plugin code or how they should be modified to match v7.0.0. The portions I'd added to the old plugin are as follows: // add the skip button HTML, add "unsure" to data as response, button is on right of screen
html += '<div class="jspsych-odd-one-out-button" style="display:block; position:fixed; width:13vw; left:calc(90vw - 8.5vw); bottom:0; margin:2vw;'+trial.margin_vertical+' '+trial.margin_horizontal+'" id="skip-button" data-choice="unsure"><button class="jspsych-btn" style="visibility:hidden;" onclick=bloop.play()>'+"I don't know >"+'</button></div>';
display_element.innerHTML = html;
// timer to change the skip button to visible after 1 minute
jsPsych.pluginAPI.setTimeout(function(){
// get the skip-button div, then get all of the button elements inside of it, then select the first (only) one
document.getElementById('skip-button').getElementsByTagName('button')[0].style.visibility = "visible";
}, 60000);
// add click event listener to skip button
display_element.querySelector('#skip-button').addEventListener('click', function(e){
var choice = e.currentTarget.getAttribute('data-choice'); // don't use dataset for jsdom compatibility
after_response(choice);
});
// kill any remaining setTimeout handlers (at end of trial)
jsPsych.pluginAPI.clearAllTimeouts(); Do you have any advice on how I should incorporate this into the new version? Thank you, |
Beta Was this translation helpful? Give feedback.
-
Here is my experiment that i am trying to migrate to 7.0.0. I made all the changes on the migration guide, but I obviously missed something. Let me know if you can spot it. Thank you ! |
Beta Was this translation helpful? Give feedback.
-
Hi everyone! I am struggling to understand how to set up jsPsych 7.0.0. I am trying to follow the tutorial on the jsPsych website, with the goal of downloading and hosting jsPsych on my computer. I downloaded [email protected] from the GitHub releases page and began to follow the Hello World tutorial for hosting jsPsych on one's computer. However, Step 2 of the tutorial says to "copy the contents of the dist folder", but I cannot find any folder called "dist." I also cannot find any file called "jspsych.js" or any files called "[plugin name].js." If you cannot tell, I'm a bit of a technophobe XD so if someone could clarify the process of downloading and hosting jsPsych on one's computer, I would be grateful! |
Beta Was this translation helpful? Give feedback.
-
Hi there, I'm trying to migrate to [email protected] from version 6 -- a painful process given that the documentation seems not to be up to date. Typically, I have the following error message when I shuffle a vector using "jsPsych.randomization.shuffle":
I vaguely understand why given the new use of JsPsych. Yet, the documentation does not mention the alternative way of shuffling. Thanks! Bastien |
Beta Was this translation helpful? Give feedback.
-
Hi, var feedbackPos = {
type: 'html-keyboard-response',
stimulus: function() {
var data = jsPsych.data.get().last(1).values()[0];
if(data.accuracy){
document.body.style.background = fdbColorCorrect;
return "Correct!"; //"Richtig!"
} else if (data.response == null) {
document.body.style.background = fdbColorIncorrect;
return "Too slow!"; //"Zu langsam!";
} else {
document.body.style.background = fdbColorIncorrect;
return "Wrong"; //"Falsch!"
}
},
choices: jsPsych.NO_KEYS,
trial_duration: trainingFeedbackDuration,
data: { trialPart: 'feedback' },
on_finish: function(){
document.body.style.background = backgroundColor;
}
}; But this leads to a migration error and I have no idea how to solve it. |
Beta Was this translation helpful? Give feedback.
-
Hello, I am attempting to make the move from jsPsych 6.3 to 7 but am running into some scope issues, I think. My experiment is spread out across multiple JavaScript source files that are compiled at runtime with webpack. I have an
The timeline function calls and imports additional scripts to help build trials, styling, etc.. In one of those scripts I access Is there a way to initiate jspsych in one file and have it callable across other separate experiment files? I feel like there is an easy solution that I am overlooking! Any help would be appreciated. |
Beta Was this translation helpful? Give feedback.
-
Hello! I am trying to migrate a custom plugin from jsPsych 6.3 to 7.2. I started with a mix of @YoannJulliard's multiple slider plugin and the original I've then tried to update this custom plugin to jsPsych 7 and get the following error message:
My plugin code is as follows: var jsPsychMultipleSlider = (function(jspsych) {
'use strict';
const info = {
name: 'multiple-slider',
description: '',
parameters: {
questions: {
type: jspsych.ParameterType.COMPLEX,
array: true,
pretty_name: 'Questions',
nested: {
/** The HTML string to be displayed */
stimulus: {
type: jspsych.ParameterType.HTML_STRING,
pretty_name: "Stimulus",
default: "",
},
prompt: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Prompt',
default: undefined,
description: 'Content to be displayed below the stimulus and above the slider'
},
// Labels to appear to the left of each slider, one in line with the top row ticks and one in line with the bottom
labels: {
type: jspsych.ParameterType.STRING,
pretty_name:'Labels',
default: [],
array: true,
description: 'Labels of the sliders.',
},
/** Array containing the ticks to show along the slider. Ticks will be displayed at equidistant locations along the slider. Note this parameter is called Labels in the original plugin.*/
ticks: {
type: jspsych.ParameterType.HTML_STRING,
pretty_name:'Ticks',
default: [],
array: true,
description: 'Ticks of the sliders.',
},
name: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Question Name',
default: '',
description: 'Controls the name of data values associated with this question'
},
min: {
type: jspsych.ParameterType.INT,
pretty_name: 'Min slider',
default: 0,
description: 'Sets the minimum value of the slider.'
},
max: {
type: jspsych.ParameterType.INT,
pretty_name: 'Max slider',
default: 100,
description: 'Sets the maximum value of the slider',
},
slider_start: {
type: jspsych.ParameterType.INT,
pretty_name: 'Slider starting value',
default: 50,
description: 'Sets the starting value of the slider',
},
step: {
type: jspsych.ParameterType.INT,
pretty_name: 'Step',
default: 1,
description: 'Sets the step of the slider'
}
}
},
randomize_question_order: {
type: jspsych.ParameterType.BOOL,
pretty_name: 'Randomize Question Order',
default: false,
description: 'If true, the order of the questions will be randomized'
},
preamble: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Preamble',
default: null,
description: 'String to display at top of the page.'
},
button_label: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Button label',
default: 'Continue',
description: 'Label of the button.'
},
autocomplete: {
type: jspsych.ParameterType.BOOL,
pretty_name: 'Allow autocomplete',
default: false,
description: "Setting this to true will enable browser auto-complete or auto-fill for the form."
},
require_movement: {
type: jspsych.ParameterType.BOOL,
pretty_name: 'Require movement',
default: false,
description: 'If true, the participant will have to move the slider before continuing.'
},
slider_width: {
type: jspsych.ParameterType.INT,
pretty_name:'Slider width',
default: 500,
description: 'Width of the slider in pixels.'
}
}
}
class MultipleSliderPlugin {
constructor(jsPsych) {
this.jsPsych = jsPsych;
}
trial(display_element, trial) {
// half of the thumb width value from jspsych.css, used to adjust the label positions
var half_thumb_width = 7.5;
var html = '<div id="jspsych-html-slider-response-wrapper" style="margin: 100px 0px;">';
html += '<div class="jspsych-html-slider-response-container" style="position:relative; margin: 0 auto 3em auto; ';
if(trial.slider_width !== null){
html += 'width:'+trial.slider_width+'px;';
} else {
html += 'width:auto;';
}
html += '">';
// show preamble text
if(trial.preamble !== null){
html += '<div id="jspsych-multiple-slider-preamble" class="jspsych-multiple-slider-preamble">'+trial.preamble+'</div>';
}
if ( trial.autocomplete ) {
html += '<form id="jspsych-multiple-slider-form">';
} else {
html += '<form id="jspsych-multiple-slider-form" autocomplete="off">';
}
// add sliders questions ///
// generate question order. this is randomized here as opposed to randomizing the order of trial.questions
// so that the data are always associated with the same question regardless of order
var question_order = [];
for(var i=0; i<trial.questions.length; i++){
question_order.push(i);
}
if(trial.randomize_question_order){
question_order = this.jsPsych.randomization.shuffle(question_order);
}
for (var i = 0; i < trial.questions.length; i++) {
var question = trial.questions[question_order[i]];
// Add stimulus
html += '<div id="jspsych-html-slider-response-stimulus">' + question.stimulus + '</div>';
// add prompt
html += '<label class="jspsych-multiple-slider-statement">' + question.prompt + '</label><br>';
// add top left label
html += '<div style="font-size: 100%; font-weight: bold; position: absolute; left: calc(-30%)">' + question.labels[0] + '</div>'
// html += '<div style="font-size: 100%; font-weight: bold; position: absolute; left: calc(-33%)">' + question.labels[1] + '</div>'
// Add top row ticks in ascending order
for(var j=0; j < question.ticks.length; j++){
var label_width_perc = 95/(question.ticks.length-1);
var percent_of_range = 5 + j * (95/(question.ticks.length - 1));
var percent_dist_from_center = ((percent_of_range-50)/50)*100;
var offset = (percent_dist_from_center * half_thumb_width)/100;
html += '<div style="border: 1px solid transparent; position: absolute; '+
'left:calc('+percent_of_range+'% - ('+label_width_perc+'% / 2) - '+offset+'px); text-align: center; width: '+label_width_perc+'%;">';
html += '<span style="text-align: center; font-size: 80%;">'+question.ticks[j]+'</span>';
html += '</div>'
}
html += '<br>'
// add sliders
html += '<input style="width: 95%; float: right" type="range" class="jspsych-html-slider-response-response" value="'+(question.slider_start)+'" min="'+question.min+'" max="'+question.max+'" step="'+question.step+'" id="jspsych-html-slider-response-response-'+i+'" name="Q'+i+'" data-name="'+question.name+'"></input><br>';
// add bottom left label
html += '<div style="font-size: 100%; font-weight: bold; position: absolute; left: calc(-30%)">' + question.labels[1] + '</div>'
// Bottom row ticks - reverse the labels list and then do the same thing as before
var reversed_ticks = question.ticks.reverse()
for(var j=0; j < question.ticks.length; j++){
var label_width_perc = 95/(question.ticks.length-1);
var percent_of_range = 5 + j * (95/(question.ticks.length - 1));
var percent_dist_from_center = ((percent_of_range-50)/50)*100;
var offset = (percent_dist_from_center * half_thumb_width)/100;
html += '<div style="border: 1px solid transparent; display: inline-block; position: absolute; '+
'left:calc('+percent_of_range+'% - ('+label_width_perc+'% / 2) - '+offset+'px); text-align: center; width: '+label_width_perc+'%;">';
html += '<span style="text-align: center; font-size: 80%;">'+reversed_ticks[j]+'</span>';
html += '</div>'
}
// add some space between the sliders
html += '<br/><br/>';
}
// add some space before the next button
html += '<br/>'
// add submit button
html += '<input type="submit" id="jspsych-multiple-slider-next" class="jspsych-multiple-slider jspsych-btn" value="'+trial.button_label+'"></input>';
html += '</form>'
html += '</div>';
html += '</div>';
display_element.innerHTML = html;
// require responses
if (trial.require_movement) {
// disable by default the next button
document.getElementById('jspsych-multiple-slider-next').disabled = true;
// check whether all sliders have been clicked
function check_reponses() {
var all_sliders = document.querySelectorAll('.jspsych-html-slider-response-response');
var all_clicked = true;
for (var i=0; i<all_sliders.length; i++) {
if (!all_sliders[i].classList.contains("clicked")) {
// if any one slider doesn't have the 'clicked' class, then we know that they haven't all been clicked
all_clicked = false;
break;
}
}
if (all_clicked) {
// if they have been clicked then enable the next button
document.getElementById('jspsych-multiple-slider-next').disabled = false;
}
}
var all_sliders = document.querySelectorAll('.jspsych-html-slider-response-response');
all_sliders.forEach(function(slider) {
slider.addEventListener('click', function() {
slider.classList.add("clicked"); // record the fact that this slider has been clicked
check_reponses(); // each time a slider is clicked, check to see if they've all been clicked
});
});
}
display_element.querySelector('#jspsych-multiple-slider-form').addEventListener('submit', function(e){
e.preventDefault();
// measure response time
var endTime = performance.now();
var response_time = endTime - startTime;
// create object to hold responses
var question_data = {};
// hold responses
var matches = display_element.querySelectorAll('input[type="range"]');
// store responses
for(var index = 0; index < matches.length; index++){
var id = matches[index].name;
var response = matches[index].valueAsNumber;
var obje = {};
if(matches[index].attributes['data-name'].value !== ''){
var name = matches[index].attributes['data-name'].value;
} else {
var name = id;
}
obje[name] = response;
Object.assign(question_data, obje);
}
// save data
var trial_data = {
"rt": response_time,
"responses": JSON.stringify(question_data),
"question_order": JSON.stringify(question_order)
};
display_element.innerHTML = '';
// next trial
this.jsPsych.finishTrial(trial_data);
});
var startTime = performance.now();
};
}
MultipleSliderPlugin.info = info;
return MultipleSliderPlugin;
})(jsPsychModule); Barring the high likelihood that I've just got a misplaced bracket or typo somewhere, I have one other idea about where the problem might be: I've looked at the guidance on how to migrate plugins and note the point on using functions like I'm sorry if this is a painfully simple problem, this plugin is really pretty hacked together because I'm very much not an experienced programmer. So any help would be much appreciated! (P.S. In case it's useful to see the experiment where I'm getting the error, it's here.) |
Beta Was this translation helpful? Give feedback.
-
I wrote a plugin (rok) for jsPsych Version 6 about a year ago. Now I adapted it to the new version 7 but I am having a hard time testing it. I cloned the jspsych-contib repository to my local system and then adapted an existing plugin (rdk). But I don’t exactly lnow how I can load the self-written plugin into an experiment. I used the ts-template. Is there an easy way to test this on my local computer? I was able to use new plugins (especially rdk) via installing them through npm: "npm install jspsych" and then npm "install @jspsych-contrib/plugin-rdk". But I don't know how I can test my own plugin (or even get it installed). |
Beta Was this translation helpful? Give feedback.
-
In the 6.x version, according to the guide, the connection to pavlovia worked well, but in 7.x, it is not connected. |
Beta Was this translation helpful? Give feedback.
-
Hello I am getting Uncaught u MigrationError: A string was provided as the trial's `type` parameter. Since jsPsych v7, the `type` parameter needs to be a plugin object. Please follow the migration guide at https://www.jspsych.org/7.0/support/migration-v7/ to update your experiment. Is it because of the types in the parameters of the info? If yes what do I change to remove it? var MyPlugin = (function (jspsych) {
"use strict";
const info = {
name: 'survey',
description: '',
parameters: {
audios: {
type: jspsych.ParameterType.COMPLEX,
array: true,
pretty_name: 'Audios',
nested: {
transcript: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Transcript',
default: '',
description: ''
},
required: {
type: jspsych.ParameterType.BOOL,
pretty_name: 'Required',
default: true,
description: ''
},
audio_name: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Audio Name',
default: '',
description: ''
}
}
},
options: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Options',
array: true,
default: ["5", "4", "3", "2", "1"],
description: ''
},
randomize_audio_order: {
type: jspsych.ParameterType.BOOL,
pretty_name: 'Randomize Audio Order',
default: false,
description: ''
},
preamble: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Preamble',
default: null,
description: ''
},
rating_info: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Rating Information',
default: "1: Bad 2: Poor 3: Fair 4: Good 5: Excellent",
description: ''
},
transcript: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Transcript All',
default: null,
description: ''
},
button_label: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Button label',
default: 'Continue',
description: 'Label of the continue button.'
},
autocomplete: {
type: jspsych.ParameterType.BOOL,
pretty_name: 'Allow autocomplete',
default: false,
description: ""
},
test_name: {
type: jspsych.ParameterType.STRING,
pretty_name: 'Test name',
default: '',
description: ''
},
}
}; |
Beta Was this translation helpful? Give feedback.
-
Hi Josh, first of all thank you for providing the community with jsPsych and this support forum here. We have tried to combine an existing RDK task built for the jsPsych version 6.1.0 with a task written for the new 7.2.1 version into one html document. We therefore changed all dependencies of the newer jsPsych task to make use of all the old version 6 plugins. That worked except for one major issue: when a response on a trial was missed, the response on the next trial measured the RT starting from the previous trial ~ the keyboardListener did not stop listening at the end of the missed trial. Thank you very much! |
Beta Was this translation helpful? Give feedback.
-
Hi, I am migrating from jsPsych 6.3 to jsPsych 7.3, and have a hard time trying to resolve the following error: The global I am sure its an easy fix. Thank you! |
Beta Was this translation helpful? Give feedback.
-
A clarification question, I'm happy with a thumbs-up if I got this right. jspsych now automatically preloads all video and audio files if it the experiment runs on a server and if jspsych finds a path for them in the exp, e.g.
|
Beta Was this translation helpful? Give feedback.
-
Hi there,
Below is the code I am trying to migrate to jsPsych 7.0:
Thank you! |
Beta Was this translation helpful? Give feedback.
-
Hi all, I'm migrating a colleague's custom plugin from 6.x to 7.3 syntax, and while I've been able to recoup most of the functionality, I'm running into a problem in appending new HTML via jQuery selection to the I've cut off the code after the break point for brevity and I've commented in the lines where I have trouble, but to recap, the problem is that I can't append an svg element.
Here's the error traceback:
Many, many thanks in advance 🙏🏻 |
Beta Was this translation helpful? Give feedback.
-
Hi there, I'm trying to run a simple experiment where I present 4 words on the screen, but when I try to run it I get the following error message:
Here is the code I'm using:
Can you please help me? Many thanks, |
Beta Was this translation helpful? Give feedback.
-
Hi,
However, it does not work on 7.X. Can you please help me? Or is there any way that can help me to upload data to GitHub? Many thanks, |
Beta Was this translation helpful? Give feedback.
-
Hello @jodeleeuw and @becky-gilbert, Here is a copy of my old working experiment: https://g8shiui5za.cognition.run/ The tasks above requires user input from the slider, but even before clicking on that if I look in the dev console environment, I can't see the trial_seq object that is in the experiment that is available in the version that actually works. I wonder if I have misunderstood how scoping works between the two instances of jspsych. Sorry if this is just a matter of placing code in the wrong area of my custom plugin, but I've tried really hard and can't figure this one out. |
Beta Was this translation helpful? Give feedback.
-
I am trying to run a jspsych task using PsiTurk on Google Chrome. The task works perfectly on my local computer, but I am getting errors when it builds the timeline when being run online. Specifically, when I try to push any var with a |
Beta Was this translation helpful? Give feedback.
-
If you've got questions about migrating your pre-7.0 experiment to v7.0, this is the thread to ask 'em in.
See our migration guide as a starting point.
Beta Was this translation helpful? Give feedback.
All reactions