2

Got a Problem with Typescript and jQuery. The elements get appended to body and show up but nothing happens when i click the button.

I suppose its something with the this.fooClick() that gets passed to the button but doesnt get called or the wrong jquery elements gets saved to the class variables.

Anyone help?

test.ts

/// <reference path="jquery.d.ts" />

class foo {

    private button;
    private text;

    constructor() {

        this.button = $('<button>').html("click").click(this.fooClick());
        this.text = $('<p>').html("foo");

        $('body').append(this.button);
        $('body').append(this.text);
    }

    public fooClick() {
        $(this.text).html("bar");
    }

}

$(function() {
    var foobar = new foo();
})

test.js

/// <reference path="jquery.d.ts" />
var foo = (function () {
    function foo() {
        this.button = $('<button>').html("click").click(this.fooClick());
        this.text = $('<p>').html("foo");
        $('body').append(this.button);
        $('body').append(this.text);
    }
    foo.prototype.fooClick = function () {
        $(this.text).html("bar");
    };
    return foo;
})();
$(function () {
    var bar = new foo();
});
1
  • 1
    .click expects to be passed a function. You are passing the return value of fooClick, which is undefined. JavaScript is not as magical as you might think. Functions to bind event listeners are no different from any other function. Whenever you have foo(bar()), bar will be executed first and its return value will be passed to foo. If you want to tell foo to execute bar at some point, you have to pass bar itself: foo(bar). Commented Apr 15, 2015 at 19:32

2 Answers 2

5

When you call .click() you want to pass it a function that can be executed when the button is clicked. Right now you are immediately executing your function:

this.button = $('<button>').html("click").click(this.fooClick());

...which will pass in the result of this.fooClick() which is undefined.

You can solve this, by passing in a function that will be executed later:

this.button = $('<button>').html("click").click(() => this.fooClick());

Note: As shown, make sure you use an arrow function to preserve the context of this.

Sign up to request clarification or add additional context in comments.

4 Comments

Both your's and @cspotcode 's answer do solve my problem, but what's the difference?
@xDreamCoding the difference is "who should be responsible for setting the scope". In this answer, the onclick handler deals with scope and leaves the class untouched, which can be more graceful that having to change your method because of how you are calling it.
@SteveFenton that's exactly it. xDreamCoding, additionally defining a function here is a solution as close to the problem as possible. Defining it on the class moves it up a step away. That increases the likelihood of a bug appearing in the future. Another dev or your future self could change it back to being on prototype. Also, another dev needs to spend more time figuring out why an arrow function was used on a class (unless a comment is provided—that's more to maintain). This way you don't have to change your class and everything is expressed at the source of the problem.
Yeah, this is the better answer. It also allows fooClick to be overridden on sub-classes and to use super to call the super-class implementation. My solution does not.
2

When registering the click handler, you must pass it a reference to the callback, not invoke the callback. Invocation will happen when the button is actually clicked.

Hence, you should do:

this.button = $('<button>').html("click").click(this.fooClick);
// notice the removed parentheses

Since fooClick expects its this value to be bound to the instance of foo, you should also rewrite it as an arrow function:

public fooClick = () => {
    $(this.text).html("bar");
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.