lhk
lhk

Reputation: 30066

Coffeescript: function can't call function on the same object

I've tried to write a simple coffeescript script. It uses easeljs to spawn a small grey circle when the user clicks the mouse. Here's the code

$(window).load ->
    game.init()


game=
    init: ->
        canvas= document.getElementById("Canvas")
        alert(canvas)
        @stage= new createjs.Stage(canvas)
        alert(@stage)

        @testshape= new createjs.Shape()
        @testshape.graphics.beginFill("#555")
        @testshape.graphics.rect(50,50,500,500)

        @stage.addChild(@testshape)
        @stage.update()

        window.onmousedown= (ev)->
            alert "click"
            mx=ev.screenX
            my=ev.screenY
            @spawn({x:mx,y:my})

    spawn: (data)->
        alert("spawn")
        x=data.x
        y=data.y

        shape = new createjs.Shape()
        shape.graphics.beginFill("#555")
        shape.graphics.circle(x,y,5)
        @stage.addChild(shape)
        @stage.update()

The first two alert calls work fine. And the testshape is created correctly. The callback is also registered fine: A mouse click prompts the alert "click". But the method spawn is never called. I didn't understand why and took a look at the generated javascript:

// Generated by CoffeeScript 1.6.1
(function() {
  var game;

  $(window).load(function() {
    return game.init();
  });

  game = {
    gameObjects: [],
    init: function() {
      var canvas;
      canvas = document.getElementById("Canvas");
      alert(canvas);
      this.stage = new createjs.Stage(canvas);
      alert(this.stage);
      this.testshape = new createjs.Shape();
      this.testshape.graphics.beginFill("#555");
      this.testshape.graphics.rect(50, 50, 500, 500);
      this.stage.addChild(this.testshape);
      this.stage.update();
      return window.onmousedown = function(ev) {
        var mx, my;
        alert("click");
        mx = ev.screenX;
        my = ev.screenY;
        return this.spawn({
          x: mx,
          y: my
        });
      };
    },
    spawn: function(data) {
      var shape, x, y;
      alert("rpcspawn");
      x = data.x;
      y = data.y;
      shape = new createjs.Shape();
      shape.graphics.beginFill("#555");
      shape.graphics.circle(x, y, 5);
      this.stage.addChild(shape);
      return this.stage.update();
    }
  };

}).call(this);

The javascript seems functional. Why is spawn not called ?

UPDATE: I've changed the code to

window.onmousedown=(ev)=>

Now the method is called correctly. But inside the method other members are not available. This alert inside spawn

alert(@stage)

Returns "undefined". I've modified spawn, too. It now uses the thick arrow syntax as well. But that didn't solve the problem. Only one method remained: init . Naturally I tried to change init to thick arrow syntax. But with all three methods using thick arrows, the original problem is back: spawn is not called.

UPDATE: I changed this to OOP programming. Game is now a class and the solution with thick arrows works

Upvotes: 1

Views: 721

Answers (2)

Craig Stuntz
Craig Stuntz

Reputation: 126547

Change your code to:

window.onmousedown= (ev)=>
        alert "click"
        mx=ev.screenX
        my=ev.screenY
        @spawn({x:mx,y:my})

(Note the =).

The problem is that, when called in the context of an event handler, @ (a.k.a. this in JavaScript) is window, not game.

Using => binds the method to game.

Upvotes: 3

Matteo Tassinari
Matteo Tassinari

Reputation: 18584

The problem here is that this, where you call this.spawn() inside your window.onmousedown callback, is actually the window object, not your game object.

You should do something like

var that = this;
return window.onmousedown = function(ev) {
    var mx, my;
    alert("click");
    mx = ev.screenX;
    my = ev.screenY;
    return that.spawn({
      x: mx,
      y: my
    });
  };

Upvotes: 0

Related Questions