TypeError: obj.contains is not a function when using variable clickable stimuli

URL of experiment: Sign in · GitLab (permissions set to internal)

Description of the problem: I’m currently trying to get an experiment up and running on Pavlovia. The task works perfectly when run from PsychoPy. I’m currently getting the following error and don’t know where I’m going wrong.

  • TypeError: mouse_2.isPressedIn is not a function

which relates to the following routine and code component.

Begin experiment
segments_1 = [polygon1, polygon2, polygon3, polygon4, polygon5, polygon6, polygon7, polygon8, polygon9, polygon10, polygon11, polygon12, polygon13, polygon14, polygon15, polygon16, polygon17, polygon18, polygon19, polygon20]

Begin routine
for (var i = 0; i < segments_1.length; i++)
{
segments_1[i].fillColor = ‘white’;
segments_1[i].lineColor = ‘black’;
}
resetSegments = false;

Each frame
var segmentIndex;

for (var i = 0; i < segments_1.length; i++)
{
if (mouse_2.isPressedIn(segments_1[i]))
{
segmentIndex = i;
resetSegments = true;
}
}

if (resetSegments)
{
for (var i = 0; i < segments_1.length; i++)
{
segments_1[i].fillColor = ‘white’;
}
resetSegments = false;
}

if (segmentIndex != null)
{
for (var i = 0; i < segmentIndex; i++)
{
segments_1[i].fillColor = ‘black’;
}
}

Hi @slorimer, the isPressedIn function is not currently available in the PsychoJS library. However, here is an example of how to code your task manually to check if a mouse is clicked in an object.

msg = '';
if (mouse.getPressed()[0] === 1) { // If left mouse button pressed 
  clickable = [SomeObject, AnotherObject];  // clickable stim
  for (const obj of clickable) {  // for each clickable stim, check if it contains the mouse
    if (obj.contains(mouse)) {
      msg = "You have clicked object: " + obj.name;
    }
  }
}

Hi @dvbridges,

Just trying to get the final parts of the study I was coding at the course working so I can run it online. I was unable to set one of the images as none in the online version so instead am trying to alter what the clickable stimuli are.

I have some code at the beginning of the routine which sets clicks:
clicks = [LeftStim,RightStim]
or clicks=[LeftStim]
That part is working fine but when we get to the part of the script that
checks for valid clicks I get the error obj.contains is not a function
I think this is because clicks is an array of two images. Is there a way round this?

    for (const obj of [clicks]) {
      if (obj.contains(choice)) {
        gotValidClick = true;
        choice.clicked_name.push(obj.name)
        choice.clicked_image.push(obj.image)
        choice.clicked_pos.push(obj.pos)
      }
    } 

Cheers,
Alice

Hi @am8302, yes I think you just need to remove the square brackets from your clicks variable. You should not need these as clicks is already an array:

for (const obj of clicks) {
  ...

Thanks @dvbridges. Is there a way to do this from the builder view.
I define clicks in a code element and it automatically compiles with the [].
Otherwiswe I guess I edit the compled .js file and then command line push to gitlab?

Yes, instead of defining a variable called clicks in a code component which is a list of all your clickable objects, just write the clickable objects into the mouse component in the parameter called Clickable stimuli

Not sure I follow. If I use the clickable stim in mouse component I can’t change this depending on conditions. Under one condition there are two clickable stim but only one under another - so I think I need to define it via code.

e.g

if (stimA!=undefined) {
    stimL = stimList[(stimA)-1]
    clicks= LeftStim,RightStim
    }
else {
stimL = "stimuli/Empty.png"
clicks=RightStim}

if (stimB!=undefined){
    stimR = stimList[(stimB)-1]
        clicks= LeftStim,RightStim
    }
else {
    stimR = "stimuli/Empty.png"
    RightStim.size=[0,0]
    clicks=LeftStim}

My alternative option is to set one of the stimuli to ‘none’ which is what I can do in the Python version but I don’t know how to do this in JavaScript so instead have inserted a grey square so it appears as if nothing is being presented. For the python version the following worked but I can’t translate it to JavaScript.

if stimA:
    stimL = stimList[int(stimA)-1]
else:
    stimL = None

if stimB:
    stimR = stimList[int(stimB)-1]
else:
    stimR = None

If you have all your clickable stimuli set in the mouse component dialog it saves having to define a clicks variable. Then, rather than set the image to none, you can change the size of the unwanted image to 0, and that is equivalent to it not being drawn.

E.g.,

image.setSize([0, 0])

I have been getting this error when using the method described for using the builder - setting the clickable stimuli. I find that it works if I just list the clickable stimuli, but it does not work if I try to use a variable. That is, I cannot change the clickable stimulus from trial to trial.

I am listing the clickable stimuli in the xlsx in a 2nd column next to a corresponsing list of audio stimulus files. The column is named ‘button’. If I put ‘$button’ in clickable stimuli I get “$button: reference is not defined”. If I put just ‘button’, I get “TypeError: obj.contains is not a function”.

I am suspecting that a double reference is needed, because the button is already a variable, so we have a variable containing a variable name, but I don’t know the syntax.

I’m getting this error in the latest version of PsychoPy (2021.2.3).

I’d like to use a variable because the clickable stimuli are based on a list of images (called images) created in code.

images.append(visual.ImageStim(
    win=win,
    name='animal'+str(animals.thisN), 
    image='animals/'+Image1, ori=0, 
    pos=locations[animals.thisN],
    size=[scale*imageRatio,scale],
    color='white', colorSpace='rgb', opacity=1,
    flipHoriz=False, flipVert=False,
    texRes=128, interpolate=True)
    )

I then recreate the clickable list every loop to remove the previously chosen image:

for Idx in range(nAnimals):
    if Idx not in chosen:
        images[Idx].setAutoDraw(True)
        clickable.append(images[Idx])

I’ve put clickable as the clickable stimuli which works offline but gives the * TypeError: obj.contains is not a function error online because of the added square brackets.

for (const obj of [clickable]) {
            if (obj.contains(mouse)) {
              gotValidClick = true;
              mouse.clicked_name.push(obj.name)
            }
          }

I don’t want to have to edit the JS files directly so I’ll probably have to check for mouse clicks in code rather than use the mouse object, or manually add image[0], image[1], … up to the maximum number of images I think I’ll need and then use the size parameter to hide instead of autodraw.

Hi! Idk if it was posted earlier on the forum, but I found a workaround without editing the .js file and decided to leave it here in case someone needs it.

If you put ...clickable in the Clickable stimuli field for your Mouse component in the builder, it will generate the following JS code:

gotValidClick = false;
for (const obj of [...clickable]) {
  if (obj.contains(mouse)) {
    gotValidClick = true;
    mouse.clicked_name.push(obj.name)
  }
}

...clickable unpacks and [...clickable] turns into clickable

1 Like