0

I've just started playing with jQuery, and created a simple function. It is working fine, except that fact, that it is active and keep working only for the first time. (The function itself is something like Select List). When you click that again it is not responding.

    $('.selected').click(function(){
            $(this).removeClass('selected').addClass('selectoption');
            $('.selectoption').show().click(function(){
                $(this).removeClass('selectoption').addClass('selected');
                $('.selectoption').hide();
            });
        return true;
    });
.selectoption {
    display: none;
    float: right;
    clear: both;
    margin-top: 3px;
    padding: 5px 10px 5px 10px;
    text-align: right;
    color: #FFFFFF;
    background: #3399FF;
    border: solid #ffcc00 1px;
}
.selected {
    display: block;
    border-bottom: dashed #3399FF 1px;
}
<div style="display: block; position: absolute; top: 32px; right: 220px; border: 0;">
                            <a href="#" class="selected">1</a>
                            <a href="#" class="selectoption">2</a>
                            <a href="#" class="selectoption">3</a>
                            <a href="#" class="selectoption">4</a>
                        </div>
drewkrit
  • 33
  • 4
  • http://stackoverflow.com/questions/3731361/click-event-executed-only-the-first-time http://stackoverflow.com/questions/10194728/jquery-click-event-works-only-once and many – ɹɐqʞɐ zoɹǝɟ Nov 06 '15 at 13:34
  • I suggest you open the debugger in your browser and place a breakpoint in each of your click handlers. I suspect you'll find that both click handlers are running and each one performs the inverse of the other so you don't see any net change. – dsh Nov 06 '15 at 13:38

2 Answers2

2

.click() only binds to DOM nodes that exist at the time that you are binding the event. Your code assumes the events bind to DOM nodes that exist when the event itself happens.

This first line binds the click function only to the elements which currently have the '.selected' class -- so only the first anchor tag in your HTML has a click event bound to it. Call this event A:

$('.selected').click(function(){
        $(this).removeClass('selected').addClass('selectoption');

On clicking that first anchor, you bind a new click event to all four of the anchors (because you've removed the '.selected' class from the first anchor and added '.selectoption'). Call this event B:

        $('.selectoption').show().click(function(){
            $(this).removeClass('selectoption').addClass('selected');
            $('.selectoption').hide();
        });
    return true;
});

So after your first click on anchor 1, anchor 1 will fire both event A and event B when next clicked (binding a new event to the same element doesn't replace the existing event). The remaining anchors will fire event B only.

The behavior you actually want can be achieved by using .on() on a parent element -- this effectively binds the events to a CSS selector instead of to specific DOM nodes, so that when the user clicks the parent element, your code will check to see if the clicked target matches the class selector:

    $('.parent')
      .on('click', '.selected', function(evt) {
        $(evt.target).removeClass('selected').addClass('selectoption');
      }).on('click', '.selectoption', function(evt) {
        $('.selected').removeClass('selected').addClass('selectoption');
        $(evt.target).removeClass('selectoption').addClass('selected');
      });
.selected {
  background-color: #F00
}
.selectoption {
  background-color: #0F0
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
  <a href="#" class="selected">1</a>
  <a href="#" class="selectoption">2</a>
  <a href="#" class="selectoption">3</a>
  <a href="#" class="selectoption">4</a>
</div>
(I removed the hide() and show() and changed the css rules to make it easier to see what's going on, but otherwise this behaves as I think you intended it to.)

So now two click events are bound to .parent; the first will fire if the click target inside parent matches .select, and the second will fire if the click target matches .selectoption -- and unlike your original code the class matching is live, so you can safely change the classes on the DOM elements, or add new elements after binding the events and have the behavior follow the new classnames.

Read up on 'delegated events' here for more detail: http://api.jquery.com/on/

Daniel Beck
  • 20,653
  • 5
  • 38
  • 53
0

You are removing a class, so it cannot be found anymore. It's best to add an extra class to listen to the click

<div style="display: block; position: absolute; top: 32px; right: 220px; border: 0;">
    <a href="#" class="option selected">1</a>
    <a href="#" class="option">2</a>
    <a href="#" class="option">3</a>
    <a href="#" class="option">4</a>
</div>

And then simplify your script into

$('.option').click(function() {
    $(".option").removeClass('selected'); // we need to remove all selected classes first ;)
    $(this).addClass('selected');
    return true;
});
Alvin Bakker
  • 1,456
  • 21
  • 40
  • I'm gonna nitpick a bit, sorry. :) This code works (except that it doesn't remove the 'selected' state from the selected item if clicked, which may have been unintended behavior anyway) -- but the reason given here is incorrect: removing the class doesn't remove the event or make it 'not be found anymore'. The reason this works is because you're binding the click event to all four anchors -- if a new `.option` anchor were added after the fact, it would not pick up the event (and similarly if the option class were removed, that would not remove the event.) – Daniel Beck Nov 06 '15 at 14:23
  • True, that was just an example to help explain what's going on with the bindings. – Daniel Beck Nov 06 '15 at 14:28
  • Clear... You just went a bit further. Just think Drewkrit is looking for the simple solution in his case – Alvin Bakker Nov 06 '15 at 14:29
  • 1
    There's certainly nothing wrong with your approach, I was just being a bit pedantic about the explanation of why it works. – Daniel Beck Nov 06 '15 at 14:32