| Reference | Downloads | Github

Loop.finished=true No longer working

I think we need @apitiot here now


Are you saying above that you managed to get it working using the loopname.finished command in 2020.1?

I’ve tried it both ways in 2020.1 and not had any luck - I see that Jon has tagged in aptiot to look into it - should I just sit back and wait and see what he says?

Best wishes,

Good morning @TomH and @Bobby_Thomas,

I will be looking into it in a couple of hours. I’ll let you know as soon as the situation has been clarified.


Excellent news!

Here’s a minimal version of my study which should end in 20 correct trials (twenty clicks within the polygon) if this helps you test it (works in psychopy, not in pavlovia).


Hello again @TomH,

I have had a look at the matter. The main issue with your code is in trialRoutineBegin:

a. You want to test whether obs_dict is empty. You cannot do that using a comparison with {} in JavaScript. You would have to do:

if ((Object.keys(obs_dict).length === 0))

As a consequence, your dictionary is never initialised and so obs_dict[image] is always NaN and so it will never be equal to 2 and so you will never call trials.finished = true

When I artificially set trials.finished = true I can confirm that the routine ends.
You can give it a try by adding the following code in trialRoutineBegin:

if (object === 'p2.bmp') { trials.finished = true; skipThisTrial = true; continueRoutine = false; }

b. You want to build you dictionary using trials.trialList but trialList is not exposed in PsychoJS and, consequently, is undefined.
You could instead use the getTrial method of the TrialHandler: you can pass it an integer that is the index in the trialList:

getTrial(index = 0) { if (index < 0 || index > this.nTotal) return undefined; return this.trialList[index]; }

Does that make sense?

@Bobby_Thomas: I will have a look at your experiment now.



1 Like

@Bobby_Thomas: I am not sure I understand what you are saying.

The 3.2 approach is rather different from the 2020 approach. Are you saying that you used the same code you generated with 3.2 but changed the import to data-2020.1.js? That would indeed create some problems…

Thank you very much Alain for looking into it - that sounds excellent but i’m a little confused by it.

Could I please bother you for a small step-by-step list to get my study running as i’m a bit overwhelmed?

Very much appreciated,

@apitiot First off my study is already completed and finished (without issue) so if the problem ends up being unique to my study we can ignore it.
To get my experiment to work a few weeks ago, I simply used PsychoPy version 3.2 and ended my loop (Iter is the loop name) with this code in the End Routine panel:

if (Decision.keys[0]=='a' or Decision.keys[0] == 'l'):

and had translated it to JS code without issue.

But after the experiment was finished I wanted to update the code to work with the most recent version of PsychoPy (so it can be an updated template for any future studies)
After changing the version to ‘latest’ in experimental settings I tried changing the code segment above to:

if (Decision.keys[0]=='a' or Decision.keys[0] == 'l'):



for JS.

But after resyncing with Pavlovia again (with this new code, and the version set to ‘latest’, the loop would not actually terminate given this condition.
I then left the PsychoPy version the same (looking at the code it is 2020.1.1), and then changed the code above back to the original:

if (Decision.keys[0]=='a' or Decision.keys[0] == 'l'):

And this worked when piloting on Pavlovia.
The problem is that when I originally posted this problem, on February 25th, this combination of PsychoPy v2020 and using Iter.finished=True is what was originally causing problems and the proposed solution was to use an older PsychoPy version or to use


but when I tried it for this second post (March 27th), it appears that the combination of Iter.finished=True and PsychoPy v 2020 now works, while trials.finished=True does not work.
I was looking into this again recently because other people on the forums have been having similar issues, and I have been pushing trials.finished=True as being the solution, but it no longer seems to actually be a viable solution.

@apitiot I appreciate your help but i’ve been trying for two days to make sense of it and haven’t been able to - I don’t have the java skills to implement what you have said.

Best wishes,

Hello @TomH,

I am afraid I am fully occupied today. I will get back to you before the end of the week.


thank you very much I appreciate it.

Best wishes,

Hello Alain,

Hope all is well. Is now a better time to have a look at my project?

Best Wishes,

Hello @TomH,

With my apologies for the delay (busy days!), these are the edits I would suggest (marked with // AP):

  • in trialRoutineBegin:
if ((Object.keys(obs_dict).length === 0)) { // AP
    // if ((obs_dict === {})) {
        for (let _pj_c = 0; _pj_c < trials.nStim; ++_pj_c) { // AP
        // for (var image, _pj_c = 0, _pj_a = trials.trialList, _pj_b = _pj_a.length; (_pj_c < _pj_b); _pj_c += 1) {
        //     image = _pj_a[_pj_c];
          const trial = trials.getTrial(_pj_c); // AP
          const image = trial["object"]; // AP
          obs_dict[image] = 1;
if ((obs_dict[image] === 2)) {
        if (! _pj.in_es6(0, Object.values(obs_dict)) && (! _pj.in_es6(1, Object.values(obs_dict)))) { // AP
        // if (((! _pj.in_es6(0, obs_dict.values())) && (! _pj.in_es6(1, obs_dict.values())))) {
            trials.finished = true;
            skipThisTrial = true;
            continueRoutine = false;
    } else {
        skipThisTrial = false;

With those modifications, your code runs on my end. I cannot vouch for its operational correctness, but it does run.
Have a go and let me know how you get on!



1 Like

Hi Alain,

Thanks for taking the time.

The loop is not behaving as it is supposed to online and is behaving very strangely.

To remind you of the way the loop is supposed to work:
(1) object is correct if within 150 pixels (i.e., inside the polygon i’ve included for easy testing)
(2) if an object is answered correctly twice in a row , (i.e., on two consecutive occasions that item, e.g., cow is attempted) it drops from the loop (i.e., its value goes from 0>1>2; if it is answered incorrectly, its value in the dict drops to 0 - the values for the other objects should stay the same here and they should still be skipped if their value reaches 2)
(3) loop terminates when all objects placed in correct location twice in a row (i.e., all objects values are 2 in dict).

EDIT: The java script is behaving in the following undesirable way:
(1) if an object is answered incorrectly it seems to reset to 0 as desired
(2) it will then finish all the objects in the that round of the loop
(3) it will then demand two new full loops in which I answer the original incorrect trial correctly (i.e., it is not skipping)
(4) then it will start a final round of the loop and terminate only once it reaches the object I originally answered incorrectly

note* currently I have all values of objects in dict set to 1 for quicker testing.
note* works fine in psychopy builder

do you know whats going wrong?


Hi Tom, I had a similar problem and posted my solution here: Cannot exit loop in online Pavlovia (Using JS code component)
Hope it helps!

Thanks Amy - it was useful to have a play around with the effect of putting certain code components in different windows (end routine,each frame etc) but it didn’t fix my problem, nor did the other growing list of threads on conditional loops in the forum. Not sure where to go next.


Hi David,

I’m surprised that this works (or perhaps it doesn’t any more) since I’m pretty sure currentLoop.thisN needs to be changed to trials.thisN

Please can you clarify when you can use the custom loop name and when you have to use trials?

Best wishes,


Hi @wakecarter, online you should always use trials when making reference to loop parameters, such as thisN or finished. This is because the trials argument for each function in the JS code is a snapshot of the current state of the trial handler, e.g., current trial number etc. It was originally set up so that currentLoop should make reference to the trial handler, as in the code you will see currentLoop = <loop name>, but this will not work because you need the snapshot instead. The generated code could be changed in future so that currentLoop points to the trials snapshot for each trial.

1 Like

Ah. I took currentLoop to be an example of a custom loop name rather than something with a specific meaning.

Hi @dvbridges

I know that this topic is heavily discussed in recent months due to PsychoPy versions however none of the solutions worked for me.

PsychoPy version = v2020.2.5

What I want to do: Participants should not perform the cate_name1_last loop at all if they do not make any mistake in the previous loop (cate_name1). If they do mistakes the mistaken trial To do a mistakeless first loop minimum of 20 trials are needed

Simply they see images and they need to choose one of the two buttons to respond. If they make a mistake, the mistaken image is added to an empty list. The list that is created by only mistaken trials need to be shown in loop cate_name1_last however if they do not make any mistakes in the previous loop experiment crushes because the list is empty. So I have the following code in the Routine named rountine_1_end

if len(learning1) == 0:
    cate_name1_last.finished = True
    cate_name1_last.finished = False


if ((learning1.length === 0)) {
    cate_name1_last.finished = true;
} else {
    cate_name1_last.finished = false;

However, I get no error message, and although the list learning1 has no item loop is not terminated.
Whenever I use

> trials.finished=true

I get the following error: error

I am a bit confused about what I need to do at this point.

Many thanks