-1

So I've been trying to organize my jQuery code (which currently has everything in $(document).ready()) by implementing an object literal on the #Menu. But now the event delegation that used to work is no longer working.

HTML

<div id="Menu">
<header id="Menu-Header">
    <button id="Menu-Button" type="button" class="btn btn-default btn-lg button-menu" aria-label="Menu"> 
        <span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
        <h1>Problems</h1> 
    </button>
</header>
...
</div>

jQuery

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

var menu = {
    $menu: $('#Menu'), $menuButton: $('#Menu-Button'), 
    init: function () {
        this.$menuButton.on('mouseenter', function () {
            this.$menuButton.children('.glyphicon-menu-hamburger').hide();
            this.$menuButton.children('h1').fadeIn(200);
        });
        this.$menuButton.on('mouseleave', function () {
            this.$menuButton.children('h1').hide();
            this.$menuButton.children('.glyphicon-menu-hamburger').fadeIn(200);
            console.log("is this even working");
        });
        console.log("menu init being called");
    }
};

And while menu init being called is being printed, the other print statement doesn't show up, which I feel indicates that .on() is not being initialized correctly.

I feel like I may be making a selector typo or something, but I can't seem to figure it out.

If anyone could help me with this that would be greatly appreciated!

JSFiddle

14wml
  • 4,048
  • 11
  • 49
  • 97
  • 1
    If your code is imported in a ` – Pointy Jul 21 '16 at 19:32

2 Answers2

2

this within your callbacks doesn't point to menu. It points to the DOM nodes that fired the event.

If you want the callbacks to be executed in the context of your object, you should use $.proxy:

...on('mouseenter', $.proxy(function () {
  ...code...
}, this));

Additionally, if you execute $('#Menu') or any other jQuery selector before the DOM nodes exist on the page, the objects they return will be empty collections.

Initialize your data after the DOM is ready, or just query the DOM as part of the callbacks.

zzzzBov
  • 174,988
  • 54
  • 320
  • 367
0

The problem is here:

$menu: $('#Menu'), $menuButton: $('#Menu-Button'),

when you query menu and menu button before document is ready. If you want to use it in the way you showed on top my offer would be Dynamic Objects:

var menu = {
    get $menu(){ return $('#Menu'); },
    get $menuButton(){ return $('#Menu-Button')},
}

Dynamic property is kind of property that evaluate the value when you try to get it's value. that means query over menu tag wont call until you get value of $menu:

console.log(menu.$menu);

Another thing to mention is the this inside your event function which is different from the one on menu object. to access menu items inside this you can simply use menu variable or if you think that name may change then you can assign this to a local variable inside your init function and then use that as menu value.

Morteza Tourani
  • 3,506
  • 5
  • 41
  • 48
  • Hmmm this adds more code and the object literal itself takes up more code than just stuffing everything into `$(document).ready()`...is there a better way to organize my jQuery code instead of using the object literal model? – 14wml Jul 21 '16 at 19:43
  • @15ongm It doesn't add more than a few words to your `$menu` and `$menuButton`. BTW because init function call is inside `doc#ready` you can add them to `menu` object inside init for example `init: function() { menu.$menu = $('#menu'); ... `. – Morteza Tourani Jul 21 '16 at 19:48
  • but then can I refer to those variables ( `menu.$menu`) in other functions outside of the init function but still within `var menu ={}` definition? – 14wml Jul 21 '16 at 20:13
  • if `init` is the first one which called and other functions are called after that, of course yes. – Morteza Tourani Jul 21 '16 at 20:19