Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery click event not working while using "Module Pattern"

I'm an intermediate front-end JS developer and I'm trying the Module Pattern outlined by Chris Coyyer here.

But when I store a jQuery selector in the settings, I'm unable to use it to trigger a click event. See the below code with my comments... Any help is greatly appreciated!

var s,
TestWidget = {
  settings: {
    testButton: $("#testing")
  },
  init: function() {
    s = this.settings;
    this.bindUIActions();
  },
  bindUIActions: function() {
    console.log(s.testButton); // This works: [context: document, selector: "#testing", constructor: function, init: function, selector: ""…]

    //This doesn't work - why?????
    s.testButton.click(function() {
        //Why isn't this triggered?
        alert('testButton clicked');
    });

    /*This works, obviously:
    $('#testing').click(function() {
        alert('testButton clicked');
    });
    */

  }
};
$(document).ready(function() {
    TestWidget.init();
});
like image 448
user1399181 Avatar asked Jul 19 '13 15:07

user1399181


1 Answers

The problem is that you initialize $("#testing") before the DOM is ready, so this jQuery object is empty.

A simple solution is to put all your code in the ready callback.

Another one would be to replace

  settings: {
    testButton: $("#testing")
  },
  init: function() {
    s = this.settings;
    this.bindUIActions();
  },

with

  settings: {
  },
  init: function() {
    s = this.settings;
    s.testButton = $("#testing");
    this.bindUIActions();
  },

But it's hard to get why you use so much code for such a simple thing. You might be overusing the pattern here and it's not really clean as you have two global variables s and TestWidget when one would already be a lot.

Here's a slight variation of your code which would be, in my opinion, cleaner, while still using modules (IIFE variant) :

TestWidget = (function(){
    var settings = {};
    return {
        init: function() {
            settings.testButton = $("#testing");
            this.bindUIActions();
        },
        bindUIActions: function() {
            console.log(settings.testButton);
            settings.testButton.click(function() {
                alert('testButton clicked');
            });
        }
    }

})();
$(document).ready(function() {
    TestWidget.init();
});

settings is kept in the closure and doesn't leak in the global namespace. Note that even this version doesn't make sense if you don't do more with the module.

like image 195
Denys Séguret Avatar answered Sep 28 '22 06:09

Denys Séguret