psychopy.org | Reference | Downloads | Github

How to exit loop after certain number of trials with JavaScript?

Oops, sorry about that. The correct version is online now:
https://run.pavlovia.org/j.adams/photonorms-2/html/

My survey flows looks like this, with the user getting stuck in the Welcome__Repeat__Loop (x99 times) if they press back on the Demographics page (which enters them into the loop - if they press Next, it’s skipped):

And the current JS I have for the Welcome routine:

for (let stimulus of [Welcome__Next]) {
    if ((stimulus.contains(Welcome__Mouse)) & (ShowClickedWelcomeNext == 0)) {
        stimulus.opacity= 0.8;
    }
    else {
        stimulus.opacity= 1;
    }
}


for (let buttonName in Welcome__Mouse.clicked_name) {
    if (Welcome__Mouse.clicked_name[buttonName] == 'Welcome__Next') { 
        ShowClickedWelcomeNext = 1;
        if (ClickedWelcome__Next.status == PsychoJS.Status.FINISHED) {
            if (nReps__Welcome__Repeat__Loop > 1) {
                Welcome__Repeat__Loop.finished = true;
                }
            continueRoutine = false;
        }
    }
}

As ever - many thanks for your time and patience for looking into this! :slight_smile:

Ok, I think this might just be small issue with your for loop syntax:

First, you should use two ampersands for the if conditional in the first loop

if ((stimulus.contains(Welcome__Mouse)) && (ShowClickedWelcomeNext == 0)) {

But, i think the real issue is the use of in to iterate through your clicked_name list. You should use of to loop through the list elements, whereas in loops through the array properties:

for (let buttonName of Welcome__Mouse.clicked_name) {

Ahh thanks, okay - I’ll definitely have to read up on best practice between ‘of’ and ‘in’.

After changing ‘in’ to ‘of’ in this instance though, the ‘Next’ button has become unresponsive, and does not register as an item that’s been clicked.

Ah, yes that breaks the rest of the loop, so you need:

for (let buttonName of Welcome__Mouse.clicked_name) {
    if (buttonName == 'Welcome__Next') { 

I need to look into why this is, but to get the behaviour I think you want, you need to go into your inner loop and select the is trials option. Now the back and forward functionality works, in addition to above change.

1 Like

Ah perfect - clicking Is Trials worked! I’m not sure I would have ever stumbled upon that just by experimenting myself.

Thanks again for the help!

Great, by the way I have put in a pull request on GitHub to have this fixed.

1 Like

Hi,

I’m also trying to implement a conditional exit to a loop in JS. Every 3rd trial, if two of the 3 trials were incorrect (determined by assigned counters, which seem to be working) the message shown should change and the loop should exit. The message seems to be changing as I would like it to, it’s only the loop exit (which I have attempted using currentLoop.finished=true;) that is not working.

The JS code I have is as follows (and I have tried with and without having Is trials selected - this does not seem to make any difference here).

if (trialCounterSTM ===2||trialCounterSTM ===5||trialCounterSTM ===8||trialCounterSTM ===11||trialCounterSTM ===14||trialCounterSTM ===17||trialCounterSTM ===20){
    if (correctCount<2){
        STM.finished=true;
        msg= 'Great, now lets try a different game';
    }
    else if (correctCount>2){
        msg = 'You are so good, lets see if you can remember an extra one!';
        correctCount=0;
    }
}
else {
    msg = 'Get ready!';
}

trialCounterSTM = trialCounterSTM+1;

As always, thank you for your help!

@jretz, I deleted the code in the End routine of your pause_2 routine as it was a duplicate of the code in the begin routine tab. I replaced your if statement with something shorter for readability. When I run this using currentLoop in the begin routine tab of pause_2, it works. So, the loop ends if I get less that 2 correct by trial 2 (3rd trial presentation):

if ([2, 5, 8, 11, 14, 17, 20].indexOf(trialCounterSTM) > -1) {
    if (correctCount<2){
        currentLoop.finished = true;
        msg= 'Great, now lets try a different game';
    }
    else if (correctCount>2){
        msg = 'You are so good, lets see if you can remember an extra one!';
        correctCount=0;
    }
}
else {
    msg = 'Get ready!';
}

Perfect - that seems to be working now - thank you.

1 Like

For some reason I seem to be having more issues with this. I have another loop which does the same thing (on every 3rd trial it should exit if >=2 of the preceding 3 trials was incorrect) later in the same experiment that does not seem to be working despite me using the same code.

Depending on whether or not ‘is trials’ is selected, I get different behaviour. When ‘is trials’ is selected, it exits the loop after a single trial whether or not the trial is correct. When ‘is trials’ is not selected, the message changes as intended depending on amount correct of preceding 3 trials, but loop does not exit. FYI, in my other very similar loop you helped me with before, ‘is trials’ is selected. Both loops I am trying to exit also have nested loops within them, but I am trying to exit outside of the nested loop so I don’t think this is the issue.

The code for the loop I am having the issues with is pretty much as above but I’ll paste it below in case there is something obvious I’ve missed.

Begin experiment:

trialCounterWM = 0;

Begin routine:

console.log("trial num", trialCounterWM);
console.log("corrCount", correctCount);

if ([2, 5, 8, 11, 14, 17].indexOf(trialCounterWM) > -1) {
    if (correctCount<2){
        currentLoop.finished=true;
        msg= "Well done!";
    }
    else if (correctCount>=2){
        msg = "You are so good, let's see if you can remember an extra one!";
        correctCount=0;
    }
}
else if ([20].indexOf(trialCounterWM) > -1) {
    msg= "Well done!";
    correctCount=0;
}
else {
    msg = "Get ready!";
}

totalTime = 0;

End routine:

trialCounterWM = trialCounterWM+1;

The output in the console shows that the counters are working fine, and the messages change, so it just seems to be the currentLoop.finished = true that is not working. I also tried using the name for the loop instead of ‘currentLoop’ but that didn’t fix it. You’ll note another variable (totalTime) is being reset - that is for a nested loop within this loop and I don’t think could be interfering (but could easily be wrong!).

Sorry for all the questions - and thanks as always for your help :slight_smile: