natnai
natnai

Reputation: 564

Event Listener Not Binding

I was hoping someone would be able to tell me why calling TestProtObj.init isn't working as expected - the listener is not working all.

$(document).ready(function () {
    //set TestProtObj properties in the constructor
    var TestProtObj = function (string, target, button) {
        this.testValue = string;
        this.target = $(target);
        this.button = $(button);
    }

    //add methods to the object prototype
    TestProtObj.prototype = {

        init: function () {
            this.button.on('click', function (e) {
                e.preventDefault;
                this.returnTest();
            });
        },

        returnTest: function () {
            this.target.append(this.testValue);
        }
    }

    //initialize client code
    var testString = 'It worked!',
        targetDiv = '#target',
        button = 'button.text-button';
    //call the returnTest() method and pass in params above
    var TestConcObj = new TestProtObj(testString, targetDiv, button);
    TestConcObj.init();
});

Strangely, the following code works:

$(document).ready(function () {
    var bindListener = function () {
        $('.test').on('click', function (e) {
            e.preventDefault;
            $('.target').append('It works!');
        })
    }

    bindListener();
})

It seems that putting the function into an object literal is for some reason, causing it to fail. No errors are being thrown in the Chrome debug toolbar.

Help greatly appreciated.

JSFiddles:

#1 #2

Upvotes: 2

Views: 960

Answers (3)

natnai
natnai

Reputation: 564

I have figured it out. I was trying .live() until I stupidly realised it had been deprecated. Anyone who is trying what I tried should use the technique found in the jQuery docs, with the following snippet:

 AjaxProt.prototype = {

        init: function () {
            var thisObj = this;
            $(document).on(thisObj.event, thisObj.targetEl, function(e) {
                e.preventDefault();
                thisObj.ajaxCall();
            });
        },

This will prevent jQuery from attempting to bind the listener on a non-existent element (that is dynamically loaded) until it actually comes into existence - by quite cleverly making use of the $(document) global object.

I hope this saves someone half a day of debugging as I have just attempted to stupidly do. Cheers!

Edit: Thanks to Mouser and all the others who tried to help me overcome my own stupidity.

Upvotes: 0

Gus Ortiz
Gus Ortiz

Reputation: 662

Your class is not properly coded. Try this:

var TestProtObj = function TestProtObj(string, target, button) {
    return this.prototype.init.call(string, target, button, this);
}

TestPrtoObj.prototype.testValue = null;
TestPrtoObj.prototype.target    = null;
TestPrtoObj.prototype.button    = null;

TestProtObj.prototype.init = function init(string, target, button) {
    vat self = this;

    this.testValue = string;
    this.target    = $(target);
    this.button    = $(button);

    this.button.on('click', function (e) {
        e.preventDefault;
        self.returnTest();
    });

    return this;
}

TestProtObj.prototype.returnTest = function returnTest() {
    this.target.append(this.testValue);
}


//initialize client code
var testString = 'It worked!',
    targetDiv = '#target',
    button    = 'button.text-button';

//call the returnTest() method and pass in params above
var instance = new TestProtObj(testString, targetDiv, button);

The init method is automatically called when you create a new instance. Now the button should be responding to the click event.

Check this awesome tutorial to get more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

I recommend naming the functions, this will help you when debugging, you will see the name of your function in the stack trace instead of just [Function] or [Function anonymous] if an exception is thrown.

Hope this helps.

Upvotes: 0

Mouser
Mouser

Reputation: 13304

Just create a private variable inside this function, that refers to the TestProtObj inside the init function using the keyword this. You can reuse this variable (self) during the entire scope of the function init.

    init: function () {
        var self = this;
        this.button.on('click', function (e) {
            e.preventDefault(); //add () here.
            self.returnTest();
        });

Because JavaScript uses lexical scope this will work.

https://jsfiddle.net/p9fjamz3/14/

When you refer to this inside the event handler this.button.on('click', ... you actually are referring to the button and not to your object.

Upvotes: 2

Related Questions