Leon Gaban
Leon Gaban

Reputation: 39028

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

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');

});

Upvotes: 6

Views: 4142

Answers (5)

Dom
Dom

Reputation: 2325

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.

Upvotes: 2

raam86
raam86

Reputation: 6871

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]

Upvotes: 1

mash
mash

Reputation: 15229

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

Upvotes: 10

Faust
Faust

Reputation: 15404

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
});

Upvotes: 1

user1864610
user1864610

Reputation:

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.

Upvotes: 1

Related Questions