Using jQuery to remove & add classes to buttons, the new class added won't work with it's click function
Asked Answered
N

5

6

I have 2 buttons, click one will swap classes for both buttons.
The classes are selected and unselected.

My CodePen:
http://codepen.io/leongaban/pen/iLBvs

enter image description here

For example: click the Login button will remove it's unselected class and give it its selected class and give the Register button its unselected class.

Now the problem is that the register_unselected class doesn't work. The unselected classes are the ones that have click actions in my jQuery.

I should be able to keep clicking the gray button and turning it blue. However after clicking the first gray button (login) the new gray button register doesn't work.

Using Chrome's inspector I can clearly see that my register_unselected class has been added, yet the click function doesn't work.

enter image description here

Any ideas? How would you approach this?

// Login Tab (default : first)
$(".login_unselected").click(function(){

  console.log('clicked login');

  // Show Login Tab as selected
  $(this)
    .removeClass('login_unselected')
    .addClass('login_selected');

  // Show Register Tab as unselected
  $(this).parent().find('#tab_register')
    .removeClass('register_selected')
    .addClass('register_unselected');

});

// Register Tab
$(".register_unselected").click(function(){

  console.log('clicked register');

  // Show Login Tab as selected
  $(this)
    .removeClass('register_unselected')
    .addClass('register_selected');

  // Show Register Tab as unselected
  $(this).parent().find('#tab_login')
    .removeClass('login_selected')  
    .addClass('login_unselected');

});
Naga answered 13/6, 2013 at 22:18 Comment(2)
two words: event delegation, the click event doesn't look for elements that gain that class when it binds, just elements that exist with that class at page load. the quick fix is $(document).on('click', 'class', function(){ //normal code}); while replacing document with a static element that does not change.Assai
@Leon see my currently unvoted solution, use less than half the amount of code you're currently using. No need for it.Refluent
T
10

When you call $(".register_unselected").click() jQuery actually searches the DOM for any elements matching .register_unselected and then listens for click events on them. Since your element won't exist until after this method is called, this will have no effect.

Instead, use $("body").on("click", ".register_unselected", function(){});

You could also replace body with another selector that will always contain the element changing classes.

EDIT: Here's a forked CodePen: http://codepen.io/anon/pen/DqFuL

Tully answered 13/6, 2013 at 22:21 Comment(0)
R
2

Nobody has given the more obvious and elegant solution.

Lets clean up the CSS a little:

//instead of .login_unselected, .registerunselected  
.target {
      color: #ccc;
      background: #666;
      cursor: pointer;
}

//instead of .x_selected, .y_selected
.selected {
      color: #fff;
      background: #3399cc;
      text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
}

So the HTML is now

<ul>
    <li id="tab_login" class="target">Login</li>
    <li id="tab_register" class="target">Register</li>
</ul>

The jQuery is:

$("ul").on("click", ".target", function(){

      // Remove selected class from any that have it
      $(".target").removeClass('selected');
      // Add class to the one you're clicking on
      $(this).addClass('selected');

});

Instead of calling the class .target you can call it .unselected. From the context of your question it's likely that you don't need two separate classes, classes are made to be applied to many elements and if you need to reference them individually you have the ids already.

Also remember, you can apply many classes to an element and then override styles from one class by specifying different property values on the last class. Whichever class is applied last will override the settings of any classes already applied to it, unless values for the properties you wish to override have not been specified in the overriding class.

Refluent answered 13/6, 2013 at 22:51 Comment(4)
Oh thanks for the code example :) Actually in my local environment there are different background images (showing a shade on the left or right) for the unselected tabs. Also the text-align is different for the Login and the Register.Naga
You could apply those styles to the ids instead?Refluent
but when a tab is in the selected state there is no background image and some colors change, but I guess I could use jQuery to update the cssNaga
If you're using a two-state image, with the background-position changing on click, you can apply the background-image to the ids and the background-position to the .selected class, provided that the clicked state has the exact same offset for each image, or use a workaround.Refluent
E
1

When you assign the click handlers based on class, the handlers are set on the buttons that match that class AT THAT TIME. They won't change just because you've changed the classes. You need to implement a click handler that detects what classes are set at click time and act accordingly.

Esmeralda answered 13/6, 2013 at 22:23 Comment(0)
J
1

Use .on() to delegate the click events from a dom element that is static and contains both.

So, if at page-load, you have:

<ul id="container">
    <li class="login_selected">Login</li>
    <li class="register_unselected">Register</li>
</ul>

Then instead of using .click(), do this:

$('#container').on('click', '.login_unselected', function(){
     //do stuff
});

and

$('#container').on('click', '.register_unselected', function(){
     //do stuff
});
Jackie answered 13/6, 2013 at 22:25 Comment(0)
L
1

You can also do this

// Login Tab (default : first)
$(".login_unselected").click(function(){

  console.log('clicked login');

  // Show Login Tab as selected
  $(this)
    .removeClass('login_unselected')
    .addClass('login_selected');

  // Show Register Tab as unselected
  $(this).parent().find('#tab_register')
    .removeClass('register_selected')
    .addClass('register_unselected');

});
// Register Tab

$("#tab_register").click(function(){

  console.log('clicked register');
    if($(this).hasClass("register_unselected")){
  // Show Login Tab as selected
  $(this)
    .removeClass('register_unselected')
    .addClass('register_selected');

  // Show Register Tab as unselected
  $(this).parent().find('#tab_login')
    .removeClass('login_selected')  
    .addClass('login_unselected'); 
    }
});

Listen to the ID and then check is it's this class.

.on is faster

[http://www.jsperf.com/change-class-on-click]
Lineup answered 13/6, 2013 at 22:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.