-1

Why wouldn't this work? I thought if I add a class name to the trigger, upon opening, and then if you click the trigger that now has this class name... we could close it.

// Menu trigger
$('.menu-trigger').on('click', function(e) {
    e.preventDefault();
    $('.menu-container').fadeIn('fast');
    $(this).addClass('open');
});
$('.menu-trigger.open').on('click', function(e) {
    e.preventDefault();
    $('.menu-container').fadeOut('fast');
    $(this).removeClass('open');
});
John the Painter
  • 2,495
  • 8
  • 59
  • 101
  • possible duplicate of [Event binding on dynamically created elements?](http://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – Shaunak D Jun 24 '14 at 10:48
  • Sorry, still have to ask: Is your element with the class .menu-trigger dynamically added to the page (such as by appending it with javascript)? If not, your issue has nothing to do with event delegation (even if that solves the problem). It's because BOTH click event handlers match the selector .menu-trigger.open, so they negate each other. There is a much easier way to handle this: use the fadeToggle method as explained in my answer. – jme11 Jun 24 '14 at 11:43

3 Answers3

0

Event Delegation :

Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers.

 $('parentselector').on('click','childselector',//callbackfunction() 

here, document is just act as a parent for menu class.. It is used to specify .menu-trigger and .menu-trigger.open are individual element inside the document and .on('click' is used for dynamically created element.

$(document).on('click','.menu-trigger' function(e) {
    e.preventDefault();
    $('.menu-container').fadeIn('fast');
    $(this).addClass('open');
});
$(document).on('click','.menu-trigger.open' ,function(e) {
    e.preventDefault();
    $('.menu-container').fadeOut('fast');
    $(this).removeClass('open');
});
kamesh
  • 2,374
  • 3
  • 25
  • 33
  • Great! But why would this work over what I had? What does adding `document` to the start and the selector within the `.on` do? – John the Painter Jun 24 '14 at 10:45
  • @rdck, Learn [**Event Delegation**](http://learn.jquery.com/events/event-delegation/) – Satpal Jun 24 '14 at 10:46
  • 1
    I hope its `document` not `docuemnt` – palaѕн Jun 24 '14 at 10:48
  • Sorry for the down vote. The information you provided is accurate, but it doesn't solve the OP's issue. This will have the same result as the OP's code. That is that BOTH of these click event handlers will fire when the menu-trigger element has the open class. Therefore, the fadeIn/fadeOut will never happen because the two negate one another. – jme11 Jun 24 '14 at 12:15
0

Use event delegation for dynamically added element

$(document).on('click',".menu-trigger.open", function(e) {
    e.preventDefault();
    $('.menu-container').fadeOut('fast');
    $(this).removeClass('open');
});

Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.

Balachandran
  • 9,567
  • 1
  • 16
  • 26
0

The reason your code isn't working is that you have two separate handlers and both will fire if the element has the .open class because both selectors in your handlers apply. So, there are a couple of things you could do:

  1. Write a single handler for the .menu-trigger and use an if statement to check for the presence of the .open class, such as if($(this).hasClass('open')). If true, do your fadeOut and if false do your fadeIn.
  2. Write two handlers like you have but specifically exclude elements with the .open class from the selector in the first one like this: $('.menu-trigger:not(.menu-trigger.open)')...
  3. Remove the menu-trigger class and add a class like menu-trigger-close, then you would have two separate handlers: one for $('menu-trigger') and one for $('menu-trigger-close').
  4. OR, the best way in my opinion, use the fadeToggle method. It does all of the work for you. It checks if the element is already visible and fades it out and vice-versa. So, you don't have to add any additional classes to keep track.

The easiest way to do this: http://api.jquery.com/fadeToggle/

If all you want to do is toggle between fadeIn and fadeOut, use the fadeToggle method:

$('.menu-trigger').on('click', function(e) {
    e.preventDefault();
    $('.menu-container').fadeToggle('fast');
});
Community
  • 1
  • 1
jme11
  • 17,134
  • 2
  • 38
  • 48