jspsych/jsPsych

Accessing Timeline Variables for Dynamic Parameters

emilygoodwin opened this issue · 1 comments

The documentation on timelines provides an example section on dynamic parameters with anonymous functions, which allows the user to access potentially multiple timeline variables and combine them into one parameter for a plugin.

However I can't get the example code provided in the documentation to work: Even wrapped in an anonymous function, the jsPsych.timelineVariable('myVariable') still just returns the object, so instead of displaying e.g. a string (as in the example below) it displays [object Object].

The minimum example here is just copied from the docs. When I paste it into a fresh timeline the third plugin in the procedure results in a trial that just says [object Object] for the name part. The img src = part also does not work: from the 'file not found' error in the console I can see that it's trying to load an image called .../[object%20Object].

var face_name_procedure = {
    timeline: [
        {
            type: jsPsychHtmlKeyboardResponse,
            stimulus: '+',
            choices: "NO_KEYS",
            trial_duration: 500
        },
        {
            type: jsPsychHtmlKeyboardResponse,
            stimulus: jsPsych.timelineVariable('name'),
            trial_duration: 1000,
            choices: "NO_KEYS"
        },
        {
            type: jsPsychHtmlKeyboardResponse,
            stimulus: function(){
                var html = `
		<img src="${jsPsych.timelineVariable('face')}">
		<p>${jsPsych.timelineVariable('name', true)}</p>`;
                return html;
            },          
            choices: "NO_KEYS",
            trial_duration: 2500
        }
    ],
    timeline_variables: [
        { face: 'person-1.jpg', name: 'Alex' },
        { face: 'person-2.jpg', name: 'Beth' },
        { face: 'person-3.jpg', name: 'Chad' },
        { face: 'person-4.jpg', name: 'Dave' }
    ]
}

This is related to [this thread] (#2619), and I did try that solution as well, but it gave the same results (replacing the stimulus with stimulus : () => { return "Test name: " + jsPsych.timelineVariable("name") + "?"; },

The work-around I've been doing is to write independent functions which first iterate over the timeline_variables array, building the parameters that need to involve multiple variables, and then passing the final product as a timeline_variable. This way, no parameters are created dynamically in the actual plugin part: each parameter can be accessed with jsPsych.timelineVariable(). An example is below; however, it will not work for users who want to do truly dynamic parameters (e.g. make them dependent upon a participants' previous response).

I also would just like to understand what I'm doing wrong when implementing the solution from the docs: Is there maybe some magic to how JsPsych should be initiated, to let jsPsych know that it should delay evaluating the variables until runtime?

Thank you for your help!

Hacky work-around e.g. if you need to create a stimulus from multiple trial parameters:

const jsPsych = initJsPsych();


let timeline = [];


timeline_building_blocks = [
	{ face: 'person-1.jpg', name: 'Alex' },
	{ face: 'person-2.jpg', name: 'Beth' },
	{ face: 'person-3.jpg', name: 'Chad' },
	{ face: 'person-4.jpg', name: 'Dave' }
]
// Loop over the list of timelinevariables, and build the stimulus, other parameters you want: 
my_timeline_variables = []
timeline_building_blocks.forEach(trial => {
	var stimulus = `Here is a name: ${trial.name} and an image: <img src="${trial.face}">`;
	my_timeline_variables.push({
		stimulus: stimulus,
	})
});

// Then push my_timeline_variables to the timeline as normal, can be accessed with jsPsych.timelineVariable()
// Since the dynamic part is over:
var face_name_procedure = {
	timeline : [
		{
			type: jsPsychHtmlKeyboardResponse, 
			stimulus: jsPsych.timelineVariable('stimulus'),
			choices: "NO_KEYS",
		}],
		timeline_variables : my_timeline_variables,
}


timeline.push(face_name_procedure)
jsPsych.run(timeline);

try changing

                var html = `
		<img src="${jsPsych.timelineVariable('face')}">
		<p>${jsPsych.timelineVariable('name', true)}</p>`;
                return html;

to

                var html = `
		<img src="${jsPsych.evaluateTimelineVariable('face')}">
		<p>${jsPsych.evaluateTimelineVariable('name', true)}</p>`;
                return html;

This should at least get the MWE running.
I think you were looking at the docs for v7 instead of v8