4

I have this code : if you try to click on Button 2 or 3 you can see the right effect. Now, go back and try to click on Button 1 : nothing happens.

Why? Thanks

$('.navigatorUserButtonOff').click(function(e){
    e.preventDefault();
    $('.navigatorUserButtons').find('.navigatorUserButtonOn').removeClass().addClass('navigatorUserButtonOff');
    $(this).removeClass().addClass('navigatorUserButtonOn');
});
user113716
  • 318,772
  • 63
  • 451
  • 440
markzzz
  • 47,390
  • 120
  • 299
  • 507

9 Answers9

3

The reason why it's not working

Because this selector you use at the beginning to bind click handler

$('.navigatorUserButtonOff')

selects only the second and third button. So you're binding click handler only them couple. First button doesn't have this class hence no click handler is bound to it.

Two posible solutions

  1. use delegate (you could use live as well but using delegate is better and works faster)

    $(".navigatorUserButtons").delegate(".navigatorUserButtonOff", "click", function(evt){
        evt.preventDefault();
        // remove and add classes as desired
    });
    

    This one will be a bit problematic because click handler will only be working on the off state buttons which means that clicking on the on state button will execute default browser behaviour that happens when you click a link. This is definitely not desired in your situation and you'll have to bind a click event to a on button as well to prevent default behaviour.

  2. A much better approach is to use a separate class that defines a button and a different one for its on/off state:

    <a class="navigatorUserButton on">...</a>
    

    And you don't need off state at all neither delegated events:

    $(".navigatorUserButton").click(function(evt){
        evt.preventDefault();
        var $this = $(this);
        if (!$this.hasClass("on"))
        {
            $this.siblings(".on").removeClass("on");
            $this.addClass("on");
        }
    });
    
Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
  • Why is delegate better than live? – JaredPar May 18 '11 at 16:58
  • 1
    @JaredPar: several reasons that have been discussed [here on stackoverflow](http://stackoverflow.com/questions/4204316/jquery-live-vs-delegate/4204349#4204349) on [many questions](http://stackoverflow.com/questions/4579117/jquery-live-vs-delegate/4579154#4579154) as well as [elsewhere on the web](http://jquerybyexample.blogspot.com/2010/08/bind-vs-live-vs-delegate-function.html). – Robert Koritnik May 18 '11 at 17:04
  • @JaredPar: I've come across it some time ago and since then I try to use `delegate` rather than `live` whenever possible. – Robert Koritnik May 18 '11 at 17:12
  • I think that the Hrant Khachatrian solution, for this case, is the best way, isnt it? faster, simple, easier... :) thanks for the great explanation! – markzzz May 20 '11 at 11:57
  • @markzzz: Whatever hits your notes. If you find it better you can use that one. I don't know why you think it's faster, because it basically does the same thing. Its also just as simple and easy to understand. But it does have a strange convention where you have two types of buttons. In my case there's just one type of buttons with added state. So they're easier to distinguish. But this is all arguable preference of personal taste. It's similar to HTML radio buttons. There's just one type of them. But they have the added state property that tells you whether they're selected or not. – Robert Koritnik May 20 '11 at 12:07
2

The reason this occurs is because the code which hooks up the events only runs once. At the time it runs button 2 and 3 meet the criteria and succesfully hookup the event. Later changes to the DOM qualify button 1 for the filter but it doesn't run again and hence button #1 doesn't get hooked up.

You can fix this by using the live function in jQuery.

$('.navigatorUserButtonOff').live('click', function(e){
  e.preventDefault();

  $('.navigatorUserButtons').find('.navigatorUserButtonOn').removeClass().addClass('navigatorUserButtonOff');
  $(this).removeClass().addClass('navigatorUserButtonOn');
});

Here is a link to a working version

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
2

Because the click event is not attached to first button. It is attached to only items that have class navigatorUserButtonOff. The first one has class of navigatorUserButtonOn. You could use the live instead

$('.navigatorUserButtonOff').live("click", function(e){
    e.preventDefault();
    $('.navigatorUserButtons').find('.navigatorUserButtonOn').removeClass().addClass('navigatorUserButtonOff');
    $(this).removeClass().addClass('navigatorUserButtonOn');
});

Demo.

amit_g
  • 30,880
  • 8
  • 61
  • 118
2

from what I've tested, if I changed the <div class="navigatorUserButtons"> <a id="view_tracklist" class="navigatorUserButtonOn" href="#">Button 1</a> and instead of navigatorUserButtonOn, you put Off, then it becomes clickable, and highlights just as the others do

Madcowe
  • 243
  • 3
  • 11
2

It's not working because the selector is filtering for elements that already have a class set to navigatorUserButtonOff, which your first button doesn't have when the document is loaded.

Brian Driscoll
  • 19,373
  • 3
  • 46
  • 65
2

That's easy one. It because you did

$('.navigatorUserButtonOff').click(...)

Which only does on click for navigatorUserButtonOff. Change it to

$('.navigatorUserButtons a').click(...)
Amir Raminfar
  • 33,777
  • 7
  • 93
  • 123
1

When the code is run, it finds all the off buttons (2 and 3, because initially 1 is on) and adds that event listener to its click event. You have to do that for all the div's children, because that function assignment is only executed one time.

Gabriel
  • 1,803
  • 1
  • 13
  • 18
1

That's because you are adding an event to all navigatorUserButtonOff and right after you did that you change the navigatorUserButtonOn to navigatorUserButtonOff so you have to add the event to the first button right after you change it

Alvaro Ardila
  • 382
  • 3
  • 10
1

Because when you are attaching the event to $('.navigatorUserButtonOff') elements, the first button is not within them! So it doesn't get the event handler. Try this:

$('.navigatorUserButtons a').click(function(e){
    e.preventDefault();
    if($(this).hasClass('navigatorUserButtonOn'))
        return false;
    $('.navigatorUserButtons').find('.navigatorUserButtonOn').removeClass().addClass('navigatorUserButtonOff');
    $(this).removeClass().addClass('navigatorUserButtonOn');
});
Hrant Khachatrian
  • 3,079
  • 24
  • 30