TypeError: Cannot read property 'concat' of undefined

URL of experiment: https://gitlab.pavlovia.org/CWoodrow/student_computer_experiment_v1

Description of the problem: When I run my experiment I get an error which says, ‘TypeError: Cannot read property ‘concat’ of undefined’. The error is in a routine which has two code components - one to allow participants to see what they type on-screen, and another to get the key durations for the keys they press. This works in PsychoPy but not in Pavlovia. The first routine that runs as intended contains the same code that allows participants to see what they type, so my assumption is that the error must be in relation to the key duration code, but I can’t figure out what.

Here is what is in my keyDuration code component:

Begin routine


mykb = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true});
mykb.start();
keysWatched = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p",
"q","r","s","t","u","v","w","x","y","z","backspace","enter","space",",",
".","/", "backslash", "'",";","[","]","1","2","3","4","5","6","7","8","9","0",
"shift", "capslock", "tab", "control", "alt", "`", "-", "=", "meta", "contextmenu",
"delete", "pound", "arrowleft", "arrowright", "arrowup", "arrowdown", "insert",
"printscreen", "home", "end", "pagedown", "pageup", "pause"];
status = ["up", "up", "up", "up", "up", 
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up"];
keyCount = 0;
currentKey = 0;
statusList = [];
pressTime = 0;
keyPressTime = [];
liftTime = 0;
keyDur=[];

Each frame

// Loop through keyboard events to update keyStates
let keyEvents = mykb.getEvents();
// Get keys?
let keys = mykb.getKeys({keyList: keysWatched, waitRelease: false, clear: false});
key_list = key_list.concat(keys);
// Previous status of key we are currently watching
let previousStatus = status[currentKey];
// Key, timestamp, and keyDown, of current key event
let keyIndex, key, keyStatus;
for (let i = 0; i < keyEvents.length; i++) {
    // Current key event
    key = keyEvents[i].pigletKey;
    keyStatus = keyEvents[i].status === Symbol.for('KEY_DOWN')? 'down': 'up';
    // Index of this key in keysWatched. NB findIndex not supported by IE
    keyIndex = keysWatched.indexOf(key);
    // Key is one that we watch; update its status
    if (keyIndex !== -1) {
        status[keyIndex] = keyStatus
        statusList.append(keyStatus)
        console.log('keyStatus')
        console.log(statusList)
    }
}
if ((statusList.length > 1)) {
    if ((statusList.slice((- 1))[0] !== statusList.slice((- 2))[0])) {
        if ((statusList.slice((- 1))[0] === "down")) {
            pressTime = taskClock.getTime() * 1000
            keyPressTime.append(pressTime)
            taskClock.reset()
        } else {
            if ((statusList.slice((- 1))[0] === "up")) {
                liftTime = taskClock.getTime() * 1000
                keyDur.append(liftTime)
                taskClock.reset()
            }
        }
    }
} else {
    if ((statusList.length == 1)) {
        pressTime = taskClock.getTime() * 1000
        keyPressTime.append(pressTime)
        taskClock.reset()
    }
}

I have tried amending the code in various ways, such as using event. instead of mykb.. I have shortened the keysWatched list to just two keys to see if the issue is related to the key names. I have also tried using .append instead of .concat. None of these have helped or changed the error at all.

Any help hugely appreciated! The full JS script can be found in the gitlab link above in the file called ‘StudentExperiment_wordsX2_v6.js’

I think this is your culprit:

key_list = key_list.concat(keys);

You’re calling ‘concat’ on key_list during the initial definition of key_list. I see why you want to do it that way, but you need to initialize it or the first time it’s quite literally trying to add onto something that doesn’t exist yet. I think if you initialize key_list with everything else in your begin routine code it should just work:

mykb = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true});
mykb.start();
keysWatched = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p",
"q","r","s","t","u","v","w","x","y","z","backspace","enter","space",",",
".","/", "backslash", "'",";","[","]","1","2","3","4","5","6","7","8","9","0",
"shift", "capslock", "tab", "control", "alt", "`", "-", "=", "meta", "contextmenu",
"delete", "pound", "arrowleft", "arrowright", "arrowup", "arrowdown", "insert",
"printscreen", "home", "end", "pagedown", "pageup", "pause"];
status = ["up", "up", "up", "up", "up", 
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up","up","up","up","up","up","up","up","up","up","up","up","up","up","up","up",
"up"];
keyCount = 0;
currentKey = 0;
statusList = [];
pressTime = 0;
keyPressTime = [];
liftTime = 0;
keyDur=[];
key_list=[]; //This line should be all you need.
1 Like

Hi @jonathan.kominsky, thanks so much for the quick response! I tried adding this to my code and am getting exactly the same error… any other ideas?

Many thanks!

Hmm. The basic issue is still likely that for whatever reason when “concat” is called, JS does not recognize that key_list has been initialized, but now I’m not sure why that is.

Can you have the log output key_list right before the concat line? It should show you an empty array. Also, if you can get a line number on the error message from the log, that would be helpful in making sure that particular instance of concat is the culprit.

@jonathan.kominsky the plot thickens! After doing some more digging and checking the log it seemed the error was actually related to the term ‘keys’. I realised that I was calling keys in a different code component in the same routine, so to see if this clash was an issue, I changed keys to keys1 in the keyDuration code.

Once I did this the error changed to ‘ReferenceError: Cannot access ‘keys’ before initialization’, and again, the error seemed to be related to my different code component. This made absolutely NO sense to me, because as I mentioned previously, that code component is identical to one in a different routine that works perfectly.

I then decided to try the experiment in a different browser (Edge) and it WORKS exactly as intended! So the issue seems to be related to Chrome, though I have no idea what. This is concerning as ideally I’d want participants to be able to access the experiment from various browsers.

For reference, here is the code in my second component that seemed to be causing an issue in Chrome. The error related to the line, keys = event.getKeys();:

Begin routine

modify = false;
text.text = " ";
event.clearEvents();

Each frame

var _pj;
function _pj_snippets(container) {
    function in_es6(left, right) {
        if (((right instanceof Array) || ((typeof right) === "string"))) {
            return (right.indexOf(left) > (- 1));
        } else {
            if (((right instanceof Map) || (right instanceof Set) || (right instanceof WeakMap) || (right instanceof WeakSet))) {
                return right.has(left);
            } else {
                return (left in right);
            }
        }
    }
    container["in_es6"] = in_es6;
    return container;
}
_pj = {};
_pj_snippets(_pj);
keys = event.getKeys();
if (keys.length) {
    if (_pj.in_es6("space", keys)) {
        text.text = (text.text + " ");
    } else {
        if (_pj.in_es6("backspace", keys)) {
            text.text = text.text.slice(0, (- 1));
        } else {
            if ((_pj.in_es6("lshift", keys) || _pj.in_es6("rshift", keys))) {
                modify = true;
            } else {
                if (_pj.in_es6("return", keys)) {
                    continueRoutine = false;
                } else {
                    if (modify) {
                        text.text = (text.text + keys[0].upper());
                        modify = false;
                    } else {
                        text.text = (text.text + keys[0]);
                    }
                }
            }
        }
    }
}

Any ideas as to why Chrome could dislike this, much appreciated!

Have you defined event as per my crib sheet or code snippets pages? If not then keys = event.getKeys(); will fail online and keys will be undefined.

Hi @wakecarter, thanks for the response. Yes, I have. My initial JS code component has the following:

Begin experiment

thisExp=psychoJS.experiment;
win=psychoJS.window;
event=psychoJS.eventManager;
shuffle = util.shuffle;
Array.prototype.append = [].push;

Also, as I mentioned, I have used keys = event.getKeys(); in a different earlier routine and this works fine.

Why are there so many psyexp files in your repository? It might be worth trying from a fresh folder.

I use Chrome and haven’t come across issues with keys = event.getKeys() with 2020.2.10 so I think I’d need to see the error live. Are you able to set the experiment to running or share it with me so I can pilot it?

Hi @wakecarter, apologies for the confusion, I had all my various experiment versions saved in one folder until things were finalised and working. I am trying to create a new repository but having sync issues so I will keep working on this.

I have added you as a member to the current (messy) repository with guest access, so let me know if you are able to run the experiment and whether you experience the same issue. The correct file is StudentExperiment_wordsX2_v6.psyexp

Your help is much appreciated!

I tried piloting it and didn’t get any errors (though it didn’t run in full screen and being asked to type before that was possible was disconcerting).

PARTICIPANT_StudentExperiment_wordsX2_v6_2021-05-04_10h34.22.135.csv (9.2 KB)

@wakecarter Thanks for letting me know it wasn’t in full screen. I think I must haver monitor settings currently set to fit my laptop, and didn’t know this would still apply in Pavlovia.

I’m still getting the error in chrome, as below:

This appears when I go to type the word ‘linear’ for the second time. It is still flagging the error at keys = event.getKeys();

Not sure why it would be fine for you and not me?

Have you tried to flush the cache using Ctrl-Shift-R ?

Did you previously have keys in a Before Experiment tab?

No, I haven’t tried that. Would you be able to explain how I do this, or direct me to somewhere with instructions?

And no, I’ve never had keys in the Before Experiment tab.

I’ve just seen that you are printing key status every frame. That looks like a significant computational overhead.

@wakecarter it works! I used Crtl+Shift+R on the experiment tab and when the page reloaded it worked! I cannot thank you enough, I never would’ve thought to try something so simple.

Re. printing key status, this is necessary to determine which keys are down and up and hence compute a press and lift time for the keys. Though if you have a better way of coding this, do let me know! This code was borrowed from one of Becca and Thomas Pronk’s experiments, as I’m a newbie myself.