Not a function?

i’m trying to create some kind of a UI manager
so far I came up with this

var UiStats = pc.createScript('uiStats');

// initialize code called once per entity
UiStats.prototype.initialize = function() {
    this.SQRButton = this.entity.findByName("CreateRedCube");
    this.RNDButton = this.entity.findByName("CreateGreenSphere");
    
    this.SQRButton.element.on('click',function (evt){
        var pressedElement = this.SQRButton;
        this.Spawn(pressedElement);
    });
    this.RNDButton.element.on('click',function (evt){
        var pressedElement = this.RNDButton;
        this.Spawn(pressedElement);
    });
};

// update code called every frame
UiStats.prototype.update = function(dt) {
    
};

UiStats.prototype.Spawn = function(entity)
{
    console.log(entity);
};

the goal is that when I click a button, the function Spawn will be executed, with that button as an argument.

however, I get an error that

Uncaught TypeError: this.Spawn is not a function

regarding

        this.Spawn(pressedElement);

What did I do wrong?

You have made a mistake with the this keyword. You should do:

UiStats.prototype.initialize = function() {
    this.SQRButton = this.entity.findByName("CreateRedCube");
    this.RNDButton = this.entity.findByName("CreateGreenSphere");
    
    this.SQRButton.element.on('click', function (evt) {
        var pressedElement = this.SQRButton;
        this.Spawn(pressedElement);
    }, this);
    this.RNDButton.element.on('click', function (evt) {
        var pressedElement = this.RNDButton;
        this.Spawn(pressedElement);
    }, this);
};

Notice how I’m passing this as the third parameter of the on function? This means the value of this is correct inside the event handler functions.

See the API reference page for pc.EventHandler#on.

Read all about the this keyword here.

1 Like

do you mean that the last this is basically just part of the on/off event syntax to define the scope of the function?

Yeah, I guess.

There’s multiple ways to achieve the same results.

  1. Pass scope as final parameter to on:
    this.SQRButton.element.on('click', function (evt) {
        var pressedElement = this.SQRButton;
        this.Spawn(pressedElement);
    }, this);
  1. Cache this in a var:
    var self = this;
    this.SQRButton.element.on('click', function (evt) {
        var pressedElement = self.SQRButton;
        self.Spawn(pressedElement);
    });
  1. Use Function.prototype.bind:
    this.SQRButton.element.on('click', function (evt) {
        var pressedElement = this.SQRButton;
        this.Spawn(pressedElement);
    }.bind(this));
  1. Use an ES6 arrow function:
    this.SQRButton.element.on('click', evt => {
        var pressedElement = this.SQRButton;
        this.Spawn(pressedElement);
    });

(Note that arrow functions don’t work in IE11.)

I would go with option 1.

2 Likes

What is the different with just using:

this.Spawn(this.SQRButton);

There isn’t, it was just part of the code from the original poster.

1 Like

Ah oke, thanks! I always try to learn.

1 Like